changeset 19312:a8d128366ebf

Merge
author Andreas Woess <andreas.woess@jku.at>
date Thu, 12 Feb 2015 04:01:46 +0100
parents a0a760b0fb5f (diff) b54b548047ac (current diff)
children a7247418a58b
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java
diffstat 189 files changed, 7180 insertions(+), 5096 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Thu Feb 12 03:42:51 2015 +0100
+++ b/CHANGELOG.md	Thu Feb 12 04:01:46 2015 +0100
@@ -19,12 +19,21 @@
 * Instrumentation:  A new example "instrumentation tool" is a language-agnostic collector of code coverage information (CoverageTracker); there are two other examples.
 
 ### Truffle-DSL
-* All methods enclosed in a @TypeSystem must now be static. 
-* All methods enclosed in generated type system classes are static.
-* Deprecated the public singleton used in the generated type system classes. 
-* NodeFactory implementations are no longer generated by default. Use {Node}Gen#create instead of {Node}Factory#create to create new instances of nodes.
+* Implemented a new generated code layout that reduces the code size.
+* Changed all methods enclosed in a @TypeSystem must now be static. 
+* Changed all methods enclosed in generated type system classes are now static.
+* Deprecated the type system constant used in the generated type system classes. 
+* Changed NodeFactory implementations are no longer generated by default. Use {Node}Gen#create instead of {Node}Factory#create to create new instances of nodes.
 * Added @GenerateNodeFactory to generate NodeFactory implementations for this node and its subclasses.
-
+* Deprecated @NodeAssumptions for removal in the next release.
+* Deprecated experimental @Implies for removal in the next release.
+* Added new package c.o.t.api.dsl.examples to the c.o.t.api.dsl project containing documented and debug-able Truffle-DSL use cases.
+* Changed "typed execute methods" are no longer required for use as specialization return type or parameter. It is now sufficient to declare them in the @TypeSystem.
+* Added @Cached annotation to express specialization local state.
+* Added Specialization#limit to declare a limit expression for the maximum number of specialization instantiations.
+* 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.
 
 ## Version 0.6
 19-Dec-2014, [Repository Revision](http://hg.openjdk.java.net/graal/graal/shortlog/graal-0.6)
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Thu Feb 12 04:01:46 2015 +0100
@@ -29,16 +29,16 @@
 import com.oracle.graal.api.meta.*;
 
 /**
- * Class for recording assumptions made during compilation. {@link OptimisticAssumption}s can only
- * be recorded in an {@link Assumptions} object if it {@linkplain #useOptimisticAssumptions()
- * allows} them.
+ * Class for recording assumptions made during compilation.
  */
 public final class Assumptions implements Serializable, Iterable<Assumptions.Assumption> {
 
     private static final long serialVersionUID = 5152062717588239131L;
 
     /**
-     * Abstract base class for assumptions.
+     * Abstract base class for assumptions. An assumption assumes a property of the runtime that may
+     * be invalidated by subsequent execution (e.g., that a class has no subclasses implementing
+     * {@link NoFinalizableSubclass Object.finalize()}).
      */
     public abstract static class Assumption implements Serializable {
 
@@ -46,23 +46,9 @@
     }
 
     /**
-     * Abstract base class for optimistic assumptions. An optimistic assumption assumes a property
-     * of the runtime that may be invalidated by subsequent execution (e.g., that a class has no
-     * subclasses implementing {@link NoFinalizableSubclass Object.finalize()}). A non-optimistic
-     * assumption assumes a property that will most likely only be invalidated by an external
-     * interface to the runtime (e.g., a {@linkplain MethodContents breakpoint is set or a class is
-     * redefined}).
+     * An assumption that a given class has no subclasses implementing {@link Object#finalize()}).
      */
-    public abstract static class OptimisticAssumption extends Assumption {
-
-        private static final long serialVersionUID = -1936652569665112932L;
-    }
-
-    /**
-     * An optimistic assumption that a given class has no subclasses implementing
-     * {@link Object#finalize()}).
-     */
-    public static final class NoFinalizableSubclass extends OptimisticAssumption {
+    public static final class NoFinalizableSubclass extends Assumption {
 
         private static final long serialVersionUID = 6451169735564055081L;
 
@@ -94,9 +80,9 @@
     }
 
     /**
-     * An optimistic assumption that a given type has a given unique subtype.
+     * An assumption that a given type has a given unique subtype.
      */
-    public static final class ConcreteSubtype extends OptimisticAssumption {
+    public static final class ConcreteSubtype extends Assumption {
 
         private static final long serialVersionUID = -1457173265437676252L;
 
@@ -142,9 +128,9 @@
     }
 
     /**
-     * An optimistic assumption that a given virtual method has a given unique implementation.
+     * An assumption that a given virtual method has a given unique implementation.
      */
-    public static final class ConcreteMethod extends OptimisticAssumption {
+    public static final class ConcreteMethod extends Assumption {
 
         private static final long serialVersionUID = -7636746737947390059L;
 
@@ -196,49 +182,9 @@
     }
 
     /**
-     * An non-optimistic assumption that the bytecodes of a given method used during compilation
-     * will not change. This kind of dependency may be used to invalidate and deoptimize compiled
-     * code when:
-     * <ul>
-     * <li>one of its constituent methods is redefined or</li>
-     * <li>a breakpoint is set in one of its constituent methods and the runtime only implements
-     * breakpoint support in non-compiled code.
-     * </ul>
+     * An assumption that a given call site's method handle did not change.
      */
-    public static final class MethodContents extends Assumption {
-
-        private static final long serialVersionUID = -4821594103928571659L;
-
-        public final ResolvedJavaMethod method;
-
-        public MethodContents(ResolvedJavaMethod method) {
-            this.method = method;
-        }
-
-        @Override
-        public int hashCode() {
-            return 31 + method.hashCode();
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof MethodContents) {
-                MethodContents other = (MethodContents) obj;
-                return other.method.equals(method);
-            }
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "MethodContents[method=" + method.format("%H.%n(%p)%r") + "]";
-        }
-    }
-
-    /**
-     * An optimistic assumption that a given call site's method handle did not change.
-     */
-    public static final class CallSiteTargetValue extends OptimisticAssumption {
+    public static final class CallSiteTargetValue extends Assumption {
 
         private static final long serialVersionUID = 1732459941784550371L;
 
@@ -274,26 +220,7 @@
         }
     }
 
-    private Set<Assumption> assumptions;
-
-    /**
-     * Specifies whether {@link OptimisticAssumption}s can be made.
-     */
-    private boolean allowOptimisticAssumptions;
-
-    public static final boolean ALLOW_OPTIMISTIC_ASSUMPTIONS = true;
-    public static final boolean DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS = false;
-
-    /**
-     * Creates an object for recording assumptions.
-     *
-     * @param allowOptimisticAssumptions specifies whether {@link OptimisticAssumption}s can be
-     *            recorded in this object
-     */
-    public Assumptions(boolean allowOptimisticAssumptions) {
-        this.allowOptimisticAssumptions = allowOptimisticAssumptions;
-        assumptions = new HashSet<>();
-    }
+    private final Set<Assumption> assumptions = new HashSet<>();
 
     /**
      * Returns whether any assumptions have been registered.
@@ -304,13 +231,6 @@
         return assumptions.isEmpty();
     }
 
-    /**
-     * Determines whether {@link OptimisticAssumption}s can be made.
-     */
-    public boolean useOptimisticAssumptions() {
-        return allowOptimisticAssumptions;
-    }
-
     @Override
     public int hashCode() {
         throw new UnsupportedOperationException("hashCode");
@@ -323,7 +243,7 @@
         }
         if (obj instanceof Assumptions) {
             Assumptions that = (Assumptions) obj;
-            if (this.allowOptimisticAssumptions != that.allowOptimisticAssumptions || !this.assumptions.equals(that.assumptions)) {
+            if (!this.assumptions.equals(that.assumptions)) {
                 return false;
             }
             return true;
@@ -368,17 +288,7 @@
         record(new ConcreteMethod(method, context, impl));
     }
 
-    /**
-     * Records that {@code method} was used during the compilation.
-     *
-     * @param method a method whose contents were used
-     */
-    public void recordMethodContents(ResolvedJavaMethod method) {
-        record(new MethodContents(method));
-    }
-
     public void record(Assumption assumption) {
-        assert allowOptimisticAssumptions || !(assumption instanceof OptimisticAssumption) : "cannot make optimistic assumption: " + assumption;
         assumptions.add(assumption);
     }
 
@@ -399,6 +309,6 @@
 
     @Override
     public String toString() {
-        return "Assumptions{optimistic=" + allowOptimisticAssumptions + ", assumptions=" + assumptions + "}";
+        return "Assumptions[" + assumptions + "]";
     }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu Feb 12 04:01:46 2015 +0100
@@ -531,6 +531,11 @@
 
     private Assumption[] assumptions;
 
+    /**
+     * The list of the methods whose bytecodes were used as input to the compilation.
+     */
+    private ResolvedJavaMethod[] methods;
+
     public CompilationResult() {
         this(null);
     }
@@ -607,18 +612,36 @@
         this.entryBCI = entryBCI;
     }
 
+    /**
+     * Sets the assumptions made during compilation.
+     */
     public void setAssumptions(Assumption[] assumptions) {
         this.assumptions = assumptions;
     }
 
     /**
-     * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the assumptions recorded in
-     * this object.
+     * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the assumptions made during
+     * compilation.
      */
     public Collection<Assumption> getAssumptions() {
         return assumptions == null ? Collections.emptyList() : Arrays.asList(assumptions);
     }
 
+    /**
+     * Sets the methods whose bytecodes were used as input to the compilation.
+     */
+    public void setMethods(ResolvedJavaMethod[] methods) {
+        this.methods = methods;
+    }
+
+    /**
+     * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the methods whose bytecodes
+     * were used as input to the compilation.
+     */
+    public Collection<ResolvedJavaMethod> getMethods() {
+        return methods == null ? Collections.emptyList() : Arrays.asList(methods);
+    }
+
     public DataSection getDataSection() {
         return dataSection;
     }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Thu Feb 12 04:01:46 2015 +0100
@@ -97,7 +97,7 @@
         } else {
             ResolvedJavaType uniqueSubtype = targetType == null ? null : targetType.findUniqueConcreteSubtype();
             if (uniqueSubtype != null) {
-                if (assumptions.useOptimisticAssumptions()) {
+                if (assumptions != null) {
                     assumptions.recordConcreteSubtype(targetType, uniqueSubtype);
                     exact = uniqueSubtype;
                 } else {
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.*;
@@ -67,8 +69,8 @@
         }
 
         // emitCode
-        Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
-        GraalCompiler.emitCode(backend, assumptions, res, compilationResult, installedCodeOwner, factory);
+        Assumptions assumptions = OptAssumptions.getValue() ? new Assumptions() : null;
+        GraalCompiler.emitCode(backend, assumptions, Collections.emptySet(), res, compilationResult, installedCodeOwner, factory);
 
         return compilationResult;
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -306,7 +305,7 @@
     }
 
     private void processMethod(final String snippet) {
-        graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new PartialEscapePhase(false, new CanonicalizerPhase(true)).apply(graph, context);
@@ -317,7 +316,7 @@
     }
 
     private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
-        graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         canonicalizer.apply(graph, context);
@@ -332,7 +331,7 @@
         new DeadCodeEliminationPhase().apply(graph);
         canonicalizer.apply(graph, context);
 
-        StructuredGraph referenceGraph = parseEager(referenceSnippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
         new InliningPhase(new CanonicalizerPhase(true)).apply(referenceGraph, context);
         new DeadCodeEliminationPhase().apply(referenceGraph);
         new CanonicalizerPhase(true).apply(referenceGraph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.debug.DelegatingDebugConfig.Feature.*;
 
 import java.io.*;
@@ -45,6 +44,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.VerifyPhase.VerificationError;
 import com.oracle.graal.phases.graph.*;
@@ -139,7 +139,7 @@
                         if (matches(filters, methodName)) {
                             executor.execute(() -> {
                                 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
-                                StructuredGraph graph = new StructuredGraph(method, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+                                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
                                 try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
                                     graphBuilderSuite.apply(graph, context);
                                     // update phi stamps
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -35,7 +35,7 @@
 public class CompareCanonicalizerTest extends GraalCompilerTest {
 
     private StructuredGraph getCanonicalizedGraph(String name) {
-        StructuredGraph graph = parseEager(name, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         return graph;
     }
@@ -48,9 +48,9 @@
 
     @Test
     public void testCanonicalComparison() {
-        StructuredGraph referenceGraph = parseEager("referenceCanonicalComparison", DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager("referenceCanonicalComparison", AllowAssumptions.NO);
         for (int i = 1; i < 4; i++) {
-            StructuredGraph graph = parseEager("canonicalCompare" + i, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager("canonicalCompare" + i, AllowAssumptions.NO);
             assertEquals(referenceGraph, graph);
         }
         new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders()));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -92,7 +91,7 @@
 
     @Test
     public void testRedundantCompares() {
-        StructuredGraph graph = parseEager("testRedundantComparesSnippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testRedundantComparesSnippet", AllowAssumptions.YES);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         PhaseContext context = new PhaseContext(getProviders());
 
@@ -115,7 +114,7 @@
     @Test
     @Ignore
     public void testInstanceOfCheckCastLowered() {
-        StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", AllowAssumptions.YES);
 
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         PhaseContext context = new PhaseContext(getProviders());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -82,12 +81,12 @@
 
     private void test(final String snippet) {
         try (Scope s = Debug.scope("DegeneratedLoopsTest", new DebugDumpScope(snippet))) {
-            StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new CanonicalizerPhase(true).apply(graph, context);
             Debug.dump(graph, "Graph");
-            StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
             Debug.dump(referenceGraph, "ReferenceGraph");
             assertEquals(referenceGraph, graph);
         } catch (Throwable e) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -107,7 +106,7 @@
     }
 
     private StructuredGraph compileSnippet(final String snippet, final int checkcasts, final int afterCanon) {
-        final StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         try (Scope s = Debug.scope("NestedCheckCastsTest", graph)) {
             Debug.dump(graph, "After parsing: " + snippet);
             Assert.assertEquals(checkcasts, graph.getNodes().filter(CheckCastNode.class).count());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,20 +22,20 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.io.*;
 import java.lang.reflect.*;
 import java.util.*;
 
 import org.junit.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.code.Assumptions.NoFinalizableSubclass;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -61,11 +61,11 @@
         }
     }
 
-    private StructuredGraph parseAndProcess(Class<?> cl, boolean allowsOptimisticAssumptions) {
+    private StructuredGraph parseAndProcess(Class<?> cl, AllowAssumptions allowAssumptions) {
         Constructor<?>[] constructors = cl.getConstructors();
         Assert.assertTrue(constructors.length == 1);
         final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]);
-        StructuredGraph graph = new StructuredGraph(javaMethod, allowsOptimisticAssumptions);
+        StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
         new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
@@ -75,13 +75,16 @@
         return graph;
     }
 
-    private void checkForRegisterFinalizeNode(Class<?> cl, boolean shouldContainFinalizer, boolean allowsOptimisticAssumptions) {
-        StructuredGraph graph = parseAndProcess(cl, allowsOptimisticAssumptions);
+    private void checkForRegisterFinalizeNode(Class<?> cl, boolean shouldContainFinalizer, AllowAssumptions allowAssumptions) {
+        StructuredGraph graph = parseAndProcess(cl, allowAssumptions);
         Assert.assertTrue(graph.getNodes().filter(RegisterFinalizerNode.class).count() == (shouldContainFinalizer ? 1 : 0));
         int noFinalizerAssumption = 0;
-        for (Assumption a : graph.getAssumptions()) {
-            if (a instanceof NoFinalizableSubclass) {
-                noFinalizerAssumption++;
+        Assumptions assumptions = graph.getAssumptions();
+        if (assumptions != null) {
+            for (Assumption a : assumptions) {
+                if (a instanceof NoFinalizableSubclass) {
+                    noFinalizerAssumption++;
+                }
             }
         }
         Assert.assertTrue(noFinalizerAssumption == (shouldContainFinalizer ? 0 : 1));
@@ -95,13 +98,13 @@
     public void test1() throws ClassNotFoundException {
         for (int i = 0; i < 2; i++) {
             ClassTemplateLoader loader = new ClassTemplateLoader();
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, AllowAssumptions.NO);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, AllowAssumptions.YES);
 
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, AllowAssumptions.YES);
 
-            checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, ALLOW_OPTIMISTIC_ASSUMPTIONS);
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, AllowAssumptions.YES);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, AllowAssumptions.YES);
         }
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
@@ -59,7 +58,7 @@
     private void test(final String snippet) {
         try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
 
-            StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             PhaseContext context = new PhaseContext(getProviders());
             new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
             new FloatingReadPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
@@ -54,6 +53,7 @@
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -72,7 +72,7 @@
  * <p>
  * White box tests for Graal compiler transformations use this pattern:
  * <ol>
- * <li>Create a graph by {@linkplain #parseEager(String, boolean) parsing} a method.</li>
+ * <li>Create a graph by {@linkplain #parseEager(String, AllowAssumptions) parsing} a method.</li>
  * <li>Manually modify the graph (e.g. replace a parameter node with a constant).</li>
  * <li>Apply a transformation to the graph.</li>
  * <li>Assert that the transformed graph is equal to an expected graph.</li>
@@ -662,7 +662,7 @@
 
     /**
      * Gets installed code for a given method, compiling it first if necessary. The graph is parsed
-     * {@link #parseEager(ResolvedJavaMethod, boolean) eagerly}.
+     * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions) eagerly}.
      */
     protected InstalledCode getCode(ResolvedJavaMethod method) {
         return getCode(method, null);
@@ -736,10 +736,10 @@
      * is null.
      *
      * The default implementation in {@link GraalCompilerTest} is to call
-     * {@link #parseEager(ResolvedJavaMethod, boolean)}.
+     * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions)}.
      */
     protected StructuredGraph parseForCompile(ResolvedJavaMethod method) {
-        return parseEager(method, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        return parseEager(method, AllowAssumptions.YES);
     }
 
     /**
@@ -816,16 +816,16 @@
      *
      * @param methodName the name of the method in {@code this.getClass()} to be parsed
      */
-    protected StructuredGraph parseProfiled(String methodName, boolean allowOptimisticAssumptions) {
-        return parseProfiled(getResolvedJavaMethod(methodName), allowOptimisticAssumptions);
+    protected StructuredGraph parseProfiled(String methodName, AllowAssumptions allowAssumptions) {
+        return parseProfiled(getResolvedJavaMethod(methodName), allowAssumptions);
     }
 
     /**
      * Parses a Java method in {@linkplain GraphBuilderConfiguration#getDefault() default} mode to
      * produce a graph.
      */
-    protected StructuredGraph parseProfiled(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
-        return parse1(m, getDefaultGraphBuilderSuite(), allowOptimisticAssumptions);
+    protected StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parse1(m, getDefaultGraphBuilderSuite(), allowAssumptions);
     }
 
     /**
@@ -834,30 +834,30 @@
      *
      * @param methodName the name of the method in {@code this.getClass()} to be parsed
      */
-    protected StructuredGraph parseEager(String methodName, boolean allowOptimisticAssumptions) {
-        return parseEager(getResolvedJavaMethod(methodName), allowOptimisticAssumptions);
+    protected StructuredGraph parseEager(String methodName, AllowAssumptions allowAssumptions) {
+        return parseEager(getResolvedJavaMethod(methodName), allowAssumptions);
     }
 
     /**
      * Parses a Java method in {@linkplain GraphBuilderConfiguration#getEagerDefault() eager} mode
      * to produce a graph.
      */
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
-        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerDefault()), allowOptimisticAssumptions);
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerDefault()), allowAssumptions);
     }
 
     /**
      * Parses a Java method in {@linkplain GraphBuilderConfiguration#getFullDebugDefault() full
      * debug} mode to produce a graph.
      */
-    protected StructuredGraph parseDebug(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
-        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()), allowOptimisticAssumptions);
+    protected StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()), allowAssumptions);
     }
 
-    private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, boolean allowOptimisticAssumptions) {
+    private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite, AllowAssumptions allowAssumptions) {
         assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
         try (Scope ds = Debug.scope("Parsing", javaMethod)) {
-            StructuredGraph graph = new StructuredGraph(javaMethod, allowOptimisticAssumptions);
+            StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
             graphBuilderSuite.apply(graph, new HighTierContext(providers, null, graphBuilderSuite, OptimisticOptimizations.ALL));
             return graph;
         } catch (Throwable e) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
 
 import org.junit.*;
@@ -30,6 +29,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -180,7 +180,7 @@
     }
 
     private void testCombinedIf(String snippet, int count) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         PhaseContext context = new PhaseContext(getProviders());
         new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         new FloatingReadPhase().apply(graph);
@@ -193,7 +193,7 @@
     }
 
     private void test(String snippet) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         ParameterNode param = graph.getNodes(ParameterNode.class).iterator().next();
         ConstantNode constant = ConstantNode.forInt(0, graph);
         for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
@@ -205,7 +205,7 @@
             fs.replaceFirstInput(param, null);
             param.safeDelete();
         }
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
@@ -38,6 +37,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -60,7 +60,7 @@
     @Test
     public void callInfopoints() {
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
-        final StructuredGraph graph = parseEager(method, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
         final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
                         OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
@@ -75,7 +75,7 @@
     @Test
     public void lineInfopoints() {
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
-        final StructuredGraph graph = parseDebug(method, OptAssumptions.getValue());
+        final StructuredGraph graph = parseDebug(method, AllowAssumptions.from(OptAssumptions.getValue()));
         int graphLineSPs = 0;
         for (FullInfopointNode ipn : graph.getNodes().filter(FullInfopointNode.class)) {
             if (ipn.getReason() == InfopointReason.LINE_NUMBER) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,11 +22,10 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -114,7 +113,7 @@
     }
 
     private StructuredGraph getCanonicalizedGraph(String snippet) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders()));
         for (FrameState state : graph.getNodes(FrameState.class).snapshot()) {
             state.replaceAtUsages(null);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import java.util.*;
 
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -61,7 +61,7 @@
     }
 
     private void test(String snippet) {
-        StructuredGraph graph = parseProfiled(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseProfiled(snippet, AllowAssumptions.NO);
         Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
             hints.put(invoke, 1000d);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -72,7 +71,7 @@
     }
 
     private void test(String snippet) {
-        StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
             hints.put(invoke, 1000d);
@@ -82,7 +81,7 @@
         new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO);
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -89,7 +88,7 @@
 
     private StructuredGraph getGraph(String snippet) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
-        StructuredGraph graph = parseEager(method, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new CanonicalizerPhase(true).apply(graph, context);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
@@ -31,6 +29,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.phases.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -122,8 +121,8 @@
     }
 
     private void test(String snippet, String referenceSnippet) {
-        final StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
-        final StructuredGraph referenceGraph = parseEager(referenceSnippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        final StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
 
         new LoopUnswitchingPhase().apply(graph);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static org.junit.Assert.*;
 
@@ -35,6 +34,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -596,7 +596,7 @@
     }
 
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
-        final StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         try (Scope d = Debug.scope("FloatingReadTest", graph)) {
             try (OverrideScope s = OptionValue.override(OptScheduleOutOfLoops, schedulingStrategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS, OptImplicitNullChecks, false)) {
                 HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -58,7 +57,7 @@
     }
 
     private void testReturnCount(String snippet, int returnCount) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         Debug.dump(graph, "Graph");
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.graph.iterators.NodePredicates.*;
 
 import java.util.*;
@@ -32,6 +31,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -84,7 +84,7 @@
     }
 
     private StructuredGraph parseAndProcess(String snippet) {
-        StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         ParameterNode param = graph.getNodes(ParameterNode.class).first();
         if (param != null) {
             ConstantNode constant = ConstantNode.forInt(0, graph);
@@ -105,7 +105,7 @@
 
     private void test(String snippet) {
         StructuredGraph graph = parseAndProcess(snippet);
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.NO);
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.java.*;
 
@@ -147,7 +146,7 @@
     }
 
     private void test(String snippet, int rootExits, int nestedExits, int innerExits) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PhiCreationTests.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PhiCreationTests.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 /**
  * In the following tests, the correct removal of redundant phis during graph building is tested.
@@ -42,7 +41,7 @@
 
     @Test
     public void test1() {
-        StructuredGraph graph = parseEager("test1Snippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
 
@@ -55,7 +54,7 @@
 
     @Test
     public void test2() {
-        StructuredGraph graph = parseEager("test2Snippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.YES);
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
 
@@ -68,7 +67,7 @@
 
     @Test
     public void test3() {
-        StructuredGraph graph = parseEager("test3Snippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("test3Snippet", AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
@@ -84,7 +83,7 @@
 
     @Test
     public void test4() {
-        StructuredGraph graph = parseEager("test4Snippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("test4Snippet", AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
@@ -31,6 +29,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
@@ -92,7 +91,7 @@
     }
 
     private StructuredGraph compileTestSnippet(final String snippet) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         PhaseContext context = new PhaseContext(getProviders());
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushThroughIfTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushThroughIfTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -58,7 +57,7 @@
     }
 
     private void test(String snippet, String reference) {
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         for (FrameState fs : graph.getNodes(FrameState.class).snapshot()) {
             fs.replaceAtUsages(null);
@@ -67,7 +66,7 @@
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
-        StructuredGraph referenceGraph = parseEager(reference, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
         for (FrameState fs : referenceGraph.getNodes(FrameState.class).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.common.*;
@@ -82,7 +81,7 @@
         try (Scope s = Debug.scope("ReadAfterCheckCastTest", new DebugDumpScope(snippet))) {
             // check shape of graph, with lots of assumptions. will probably fail if graph
             // structure changes significantly
-            StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             PhaseContext context = new PhaseContext(getProviders());
             CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
             new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -244,9 +243,9 @@
     }
 
     private <T extends Node & IterableNodeType> void test(String test, String ref) {
-        StructuredGraph testGraph = parseEager(test, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph testGraph = parseEager(test, AllowAssumptions.NO);
         new CanonicalizerPhase(true).apply(testGraph, new PhaseContext(getProviders()));
-        StructuredGraph refGraph = parseEager(ref, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph refGraph = parseEager(ref, AllowAssumptions.NO);
         new CanonicalizerPhase(true).apply(refGraph, new PhaseContext(getProviders()));
         assertEquals(testGraph, refGraph);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -131,11 +130,11 @@
 
     private void test(final String snippet, final String referenceSnippet) {
         // No debug scope to reduce console noise for @Test(expected = ...) tests
-        StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         Debug.dump(graph, "Graph");
         PhaseContext context = new PhaseContext(getProviders());
         new CanonicalizerPhase(true).apply(graph, context);
-        StructuredGraph referenceGraph = parseEager(referenceSnippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import java.util.*;
@@ -31,6 +30,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.util.*;
@@ -52,7 +52,7 @@
 
     @Test
     public void testValueProxyInputs() {
-        StructuredGraph graph = parseEager("testValueProxyInputsSnippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testValueProxyInputsSnippet", AllowAssumptions.YES);
         for (FrameState fs : graph.getNodes().filter(FrameState.class).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import java.util.*;
@@ -31,6 +30,7 @@
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.cfg.*;
 
 public class SimpleCFGTest extends GraalCompilerTest {
@@ -41,7 +41,7 @@
 
     @Test
     public void testImplies() {
-        StructuredGraph graph = new StructuredGraph(ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES);
 
         AbstractEndNode trueEnd = graph.add(new EndNode());
         AbstractEndNode falseEnd = graph.add(new EndNode());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -110,7 +109,7 @@
     }
 
     private void testZeroReturn(String methodName) {
-        StructuredGraph graph = parseEager(methodName, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new DeadCodeEliminationPhase().apply(graph);
         assertConstantReturn(graph, 0);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -88,10 +87,10 @@
 
     private void test(final String snippet) {
         // No debug scope to reduce console noise for @Test(expected = ...) tests
-        StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES);
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.io.*;
 
 import org.junit.*;
@@ -32,6 +30,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
@@ -171,7 +170,7 @@
     }
 
     private void test(String snippet, String referenceSnippet) {
-        StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         Debug.dump(graph, "Graph");
         /*
          * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
@@ -182,7 +181,7 @@
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         // a second canonicalizer is needed to process nested MaterializeNodes
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
-        StructuredGraph referenceGraph = parseEager(referenceSnippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
         new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders()));
         assertEquals(referenceGraph, graph);
     }
@@ -230,7 +229,7 @@
     }
 
     private <T extends Node> void testHelper(String snippet, Class<T> clazz) {
-        StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         Debug.dump(graph, "Graph " + snippet);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test.backend;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -36,11 +34,12 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 public class AllocatorTest extends BackendTest {
 
     protected void testAllocation(String snippet, final int expectedRegisters, final int expectedRegRegMoves, final int expectedSpillMoves) {
-        final StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         try (Scope s = Debug.scope("AllocatorTest", graph, graph.method(), getCodeCache())) {
             final RegisterStats stats = new RegisterStats(getLIRGenerationResult(graph).getLIR());
             try (Scope s2 = Debug.scope("Assertions", stats.lir)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.test.backend;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.compiler.*;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.compiler.test.deopt;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -53,7 +52,7 @@
     @Test
     public void test1() {
         final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod");
-        final StructuredGraph graph = parseEager(javaMethod, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.NO);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new DeadCodeEliminationPhase().apply(graph);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,14 +24,13 @@
  */
 package com.oracle.graal.compiler.test.deopt;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 public final class MonitorDeoptTest extends GraalCompilerTest {
 
@@ -136,7 +135,7 @@
     public void run0() throws Throwable {
         ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test");
 
-        StructuredGraph graph = parseEager(javaMethod, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.YES);
         removeLoopSafepoint(graph);
 
         CompilationResult compilationResult = compile(javaMethod, graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -34,6 +32,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.*;
@@ -150,7 +149,7 @@
 
     protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
-        graph = new StructuredGraph(method, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = new StructuredGraph(method, AllowAssumptions.NO);
         try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
             new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
                             OptimisticOptimizations.ALL).apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,10 +22,9 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -41,7 +40,7 @@
 
     @Override
     protected void processMethod(final String snippet) {
-        graph = parseEager(getResolvedJavaMethod(snippet), DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = parseEager(getResolvedJavaMethod(snippet), AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new EarlyReadEliminationPhase(new CanonicalizerPhase(true)).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import java.util.concurrent.*;
@@ -32,6 +31,7 @@
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.compiler.test.ea.EATestBase.TestClassInt;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -84,7 +84,7 @@
     }
 
     private void processMethod(final String snippet) {
-        graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = parseEager(snippet, AllowAssumptions.YES);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new IterativeInliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import java.util.*;
@@ -31,6 +30,7 @@
 
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
@@ -244,7 +244,7 @@
     }
 
     protected void processMethod(final String snippet) {
-        graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = parseEager(snippet, AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new PartialEscapePhase(false, true, new CanonicalizerPhase(true), null).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test.ea;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
@@ -31,6 +29,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -60,7 +59,7 @@
 
     private void test(final String snippet) {
         try (Scope s = Debug.scope("PoorMansEATest", new DebugDumpScope(snippet))) {
-            StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
             HighTierContext highTierContext = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
             PhaseContext context = new PhaseContext(getProviders());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.compiler.test.inlining;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
@@ -35,6 +34,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -232,7 +232,7 @@
     private StructuredGraph getGraph(final String snippet, final boolean eagerInfopointMode) {
         try (Scope s = Debug.scope("InliningTest", new DebugDumpScope(snippet))) {
             ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
-            StructuredGraph graph = eagerInfopointMode ? parseDebug(method, ALLOW_OPTIMISTIC_ASSUMPTIONS) : parseEager(method, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = eagerInfopointMode ? parseDebug(method, AllowAssumptions.YES) : parseEager(method, AllowAssumptions.YES);
             PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()) : getDefaultGraphBuilderSuite();
             HighTierContext context = new HighTierContext(getProviders(), null, graphBuilderSuite, OptimisticOptimizations.ALL);
             Debug.dump(graph, "Graph");
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test.tutorial;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.lang.reflect.*;
 import java.util.*;
 import java.util.concurrent.atomic.*;
@@ -39,6 +37,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
@@ -84,7 +83,7 @@
              * that we want the compilation to make optimistic assumptions about runtime state such
              * as the loaded class hierarchy.
              */
-            StructuredGraph graph = new StructuredGraph(method, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.YES);
 
             /*
              * The phases used to build the graph. Usually this is just the GraphBuilderPhase. If
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.test.tutorial;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -34,6 +32,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
@@ -211,7 +210,7 @@
                  * Build the Graal graph for the method using the bytecode parser provided by Graal.
                  */
 
-                StructuredGraph graph = new StructuredGraph(method, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
                 /*
                  * Support for graph dumping, IGV uses this information to show the method name of a
                  * graph.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Feb 12 04:01:46 2015 +0100
@@ -279,7 +279,7 @@
             LIRGenerationResult lirGen = null;
             lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig, lirSuites);
             try (Scope s = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
-                emitCode(backend, graph.getAssumptions(), lirGen, compilationResult, installedCodeOwner, factory);
+                emitCode(backend, graph.getAssumptions(), graph.getMethods(), lirGen, compilationResult, installedCodeOwner, factory);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
@@ -363,15 +363,18 @@
         return lirGenRes;
     }
 
-    public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerationResult lirGenRes, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
-                    CompilationResultBuilderFactory factory) {
+    public static void emitCode(Backend backend, Assumptions assumptions, Set<ResolvedJavaMethod> methods, LIRGenerationResult lirGenRes, CompilationResult compilationResult,
+                    ResolvedJavaMethod installedCodeOwner, CompilationResultBuilderFactory factory) {
         FrameMap frameMap = lirGenRes.getFrameMap();
         CompilationResultBuilder crb = backend.newCompilationResultBuilder(lirGenRes, frameMap, compilationResult, factory);
         backend.emitCode(crb, lirGenRes.getLIR(), installedCodeOwner);
         crb.finish();
-        if (!assumptions.isEmpty()) {
+        if (assumptions != null && !assumptions.isEmpty()) {
             compilationResult.setAssumptions(assumptions.toArray());
         }
+        if (methods != null) {
+            compilationResult.setMethods(methods.toArray(new ResolvedJavaMethod[methods.size()]));
+        }
 
         if (Debug.isMeterEnabled()) {
             List<DataPatch> ldp = compilationResult.getDataPatches();
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
@@ -42,6 +41,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionValue.OverrideScope;
@@ -205,7 +205,7 @@
     }
 
     private StructuredGraph compile(String test, boolean compileAOT) {
-        StructuredGraph graph = parseEager(test, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(test, AllowAssumptions.YES);
         ResolvedJavaMethod method = graph.method();
 
         try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Thu Feb 12 04:01:46 2015 +0100
@@ -23,7 +23,6 @@
 
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
@@ -33,6 +32,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 public class ClassSubstitutionsTests extends GraalCompilerTest {
 
@@ -44,7 +44,7 @@
 
     protected StructuredGraph test(final String snippet) {
         try (Scope s = Debug.scope("ClassSubstitutionsTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
-            StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             compile(graph.method(), graph);
             assertNotInGraph(graph, Invoke.class);
             Debug.dump(graph, snippet);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 public class HotSpotNmethodTest extends GraalCompilerTest {
 
@@ -38,7 +37,7 @@
     @Test
     public void testInstallCodeInvalidation() {
         final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
-        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", ALLOW_OPTIMISTIC_ASSUMPTIONS));
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
         Assert.assertTrue(nmethod.isValid());
         Object result;
         try {
@@ -61,7 +60,7 @@
     @Test
     public void testInstallCodeInvalidationWhileRunning() {
         final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
-        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", ALLOW_OPTIMISTIC_ASSUMPTIONS));
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
         Object result;
         try {
             result = nmethod.executeVarargs(nmethod, null, null);
@@ -75,7 +74,7 @@
     @Test
     public void testInstalledCodeCalledFromCompiledCode() {
         final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
-        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", ALLOW_OPTIMISTIC_ASSUMPTIONS));
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
         Assert.assertTrue(nmethod.isValid());
         try {
             for (int i = 0; i < ITERATION_COUNT; ++i) {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeSubstitutionsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeSubstitutionsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,12 +22,11 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.replacements.test.*;
 
 /**
@@ -37,7 +36,7 @@
 
     @Test
     public void test() {
-        StructuredGraph graph = new StructuredGraph(ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES);
         test("getNodeClass", ConstantNode.forInt(42, graph));
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -31,6 +31,7 @@
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 public class InstalledCodeExecuteHelperTest extends GraalCompilerTest {
 
@@ -68,8 +69,8 @@
     }
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
-        StructuredGraph graph = super.parseEager(m, allowOptimisticAssumptions);
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions);
         if (argsToBind != null) {
             Object receiver = isStatic(m.getModifiers()) ? null : this;
             Object[] args = argsWithReceiver(receiver, argsToBind);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.debug.internal.MemUseTrackerImpl.*;
 import static com.oracle.graal.hotspot.CompileTheWorld.*;
 import static com.oracle.graal.hotspot.CompileTheWorld.Options.*;
@@ -35,6 +34,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.CompileTheWorld.Config;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.printer.*;
 
 /**
@@ -165,7 +165,7 @@
     private void compileAndTime(String methodName) {
 
         // Parse in eager mode to resolve methods/fields/classes
-        parseEager(methodName, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        parseEager(methodName, AllowAssumptions.YES);
 
         // Warm up and initialize compiler phases used by this compilation
         for (int i = 0; i < 10; i++) {
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.lang.ref.*;
 
 import org.junit.*;
@@ -40,6 +38,7 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -245,7 +244,7 @@
     private void testHelper(final String snippetName, final int expectedBarriers) throws Exception, SecurityException {
         ResolvedJavaMethod snippet = getResolvedJavaMethod(snippetName);
         try (Scope s = Debug.scope("WriteBarrierAdditionTest", snippet)) {
-            StructuredGraph graph = parseEager(snippet, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
             HighTierContext highContext = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
             new NodeIntrinsificationPhase(getProviders(), getSnippetReflection()).apply(graph);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -38,6 +36,7 @@
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.hotspot.replacements.arraycopy.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -627,7 +626,7 @@
 
     private void testPredicate(final String snippet, final GraphPredicate expectedBarriers, final int... removedBarrierIndices) {
         try (Scope d = Debug.scope("WriteBarrierVerificationTest", new DebugDumpScope(snippet))) {
-            final StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             HighTierContext highTierContext = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Feb 12 04:01:46 2015 +0100
@@ -213,10 +213,10 @@
                     Replacements replacements = providers.getReplacements();
                     graph = replacements.getMethodSubstitution(method);
                     if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
-                        graph = new StructuredGraph(method, entryBCI, OptAssumptions.getValue());
+                        graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
                     } else {
                         // Compiling method substitution - must clone the graph
-                        graph = graph.copy();
+                        graph = graph.copy(graph.name, method, AllowAssumptions.from(OptAssumptions.getValue()));
                     }
                     InlinedBytecodes.add(method.getCodeSize());
                     CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Feb 12 04:01:46 2015 +0100
@@ -183,7 +183,7 @@
             CallSite callSite = (CallSite) object;
             MethodHandle target = callSite.getTarget();
             if (!(callSite instanceof ConstantCallSite)) {
-                if (assumptions == null || !assumptions.useOptimisticAssumptions()) {
+                if (assumptions == null) {
                     return null;
                 }
                 assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.nfi;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.util.*;
@@ -33,6 +32,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.virtual.*;
@@ -53,7 +53,7 @@
     public static StructuredGraph getGraph(HotSpotProviders providers, RawNativeCallNodeFactory factory, long functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
         try {
             ResolvedJavaMethod method = providers.getMetaAccess().lookupJavaMethod(NativeCallStubGraphBuilder.class.getMethod("libCall", Object.class, Object.class, Object.class));
-            StructuredGraph g = new StructuredGraph(method, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph g = new StructuredGraph(method, AllowAssumptions.NO);
             ParameterNode arg0 = g.unique(new ParameterNode(0, StampFactory.forKind(Kind.Object)));
             ParameterNode arg1 = g.unique(new ParameterNode(1, StampFactory.forKind(Kind.Object)));
             ParameterNode arg2 = g.unique(new ParameterNode(2, StampFactory.forKind(Kind.Object)));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -72,7 +73,7 @@
                 Assumptions assumptions = graph().getAssumptions();
                 type = getConcreteType(getObject().stamp(), assumptions, tool.getMetaAccess());
                 if (type != null) {
-                    StructuredGraph newGraph = new StructuredGraph(assumptions.useOptimisticAssumptions());
+                    StructuredGraph newGraph = new StructuredGraph(AllowAssumptions.from(assumptions != null));
                     ParameterNode param = newGraph.unique(new ParameterNode(0, getObject().stamp()));
                     NewInstanceNode newInstance = newGraph.add(new NewInstanceNode(type, true));
                     newGraph.addAfterFixed(newGraph.start(), newInstance);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 
@@ -37,6 +36,7 @@
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.nodes.*;
@@ -191,7 +191,7 @@
         Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
         boolean isObjectResult = linkage.getOutgoingCallingConvention().getReturn().getKind() == Kind.Object;
 
-        StructuredGraph graph = new StructuredGraph(toString(), null, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO);
 
         GraphKit kit = new HotSpotGraphKit(graph, providers);
         ParameterNode[] params = createParameters(kit, args);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Thu Feb 12 04:01:46 2015 +0100
@@ -157,7 +157,7 @@
         if (code == null) {
             try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
                 final StructuredGraph graph = getGraph();
-                assert !graph.getAssumptions().useOptimisticAssumptions();
+                assert graph.getAssumptions() == null;
                 if (!(graph.start() instanceof StubStartNode)) {
                     StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
                     newStart.setStateAfter(graph.start().stateAfter());
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 /**
  * Base class for the JTT tests.
@@ -56,8 +57,8 @@
     }
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
-        StructuredGraph graph = super.parseEager(m, allowOptimisticAssumptions);
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions);
         if (argsToBind != null) {
             Object receiver = isStatic(m.getModifiers()) ? null : this;
             Object[] args = argsWithReceiver(receiver, argsToBind);
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Thu Feb 12 04:01:46 2015 +0100
@@ -117,7 +117,7 @@
 
                 List<? extends AnnotationMirror> annotations = field.getAnnotationMirrors();
 
-                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input) != null;
+                boolean isNonOptionalInput = findAnnotationMirror(annotations, Input.asType()) != null;
                 boolean isOptionalInput = findAnnotationMirror(annotations, OptionalInput) != null;
                 boolean isSuccessor = findAnnotationMirror(annotations, Successor) != null;
 
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
@@ -32,6 +31,7 @@
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 /**
  * This class tests that integer stamps are created correctly for constants.
@@ -46,7 +46,7 @@
 
     @Before
     public void before() {
-        graph = new StructuredGraph(ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = new StructuredGraph(AllowAssumptions.YES);
     }
 
     @Test
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/LoopPhiCanonicalizerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/LoopPhiCanonicalizerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.nodes.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -58,7 +57,7 @@
 
     @Test
     public void test() {
-        StructuredGraph graph = parseEager("loopSnippet", ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("loopSnippet", AllowAssumptions.YES);
         NodePredicate loopPhis = node -> node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode;
 
         PhaseContext context = new PhaseContext(getProviders());
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/NegateNodeCanonicalizationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/NegateNodeCanonicalizationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
@@ -30,6 +29,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 
 /**
  * This class tests that the canonicalization for constant negate nodes cover all cases.
@@ -40,7 +40,7 @@
 
     @Before
     public void before() {
-        graph = new StructuredGraph(ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        graph = new StructuredGraph(AllowAssumptions.YES);
     }
 
     @Test
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Feb 12 04:01:46 2015 +0100
@@ -26,7 +26,7 @@
 import java.util.concurrent.atomic.*;
 
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.OptimisticAssumption;
+import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -82,6 +82,17 @@
         }
     }
 
+    /**
+     * Constants denoting whether or not {@link Assumption}s can be made while processing a graph.
+     */
+    public enum AllowAssumptions {
+        YES,
+        NO;
+        public static AllowAssumptions from(boolean flag) {
+            return flag ? YES : NO;
+        }
+    }
+
     public static final int INVOCATION_ENTRY_BCI = -1;
     public static final long INVALID_GRAPH_ID = -1;
 
@@ -101,50 +112,41 @@
     private final Assumptions assumptions;
 
     /**
+     * The methods whose bytecodes are used while constructing this graph.
+     */
+    private Set<ResolvedJavaMethod> methods = new HashSet<>();
+
+    /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
      * start} node.
-     *
-     * @param allowOptimisticAssumptions specifies whether {@link OptimisticAssumption}s can be made
-     *            while processing the graph
      */
-    public StructuredGraph(boolean allowOptimisticAssumptions) {
-        this(null, null, allowOptimisticAssumptions);
+    public StructuredGraph(AllowAssumptions allowAssumptions) {
+        this(null, null, allowAssumptions);
     }
 
     /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
      * start} node.
-     *
-     * @param allowOptimisticAssumptions specifies whether {@link OptimisticAssumption}s can be made
-     *            while processing the graph
      */
-    public StructuredGraph(String name, ResolvedJavaMethod method, boolean allowOptimisticAssumptions) {
-        this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI, null, allowOptimisticAssumptions);
+    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
+        this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI, allowAssumptions);
     }
 
-    /**
-     * @param allowOptimisticAssumptions specifies whether {@link OptimisticAssumption}s can be made
-     *            while processing the graph
-     */
-    public StructuredGraph(ResolvedJavaMethod method, boolean allowOptimisticAssumptions) {
-        this(null, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI, null, allowOptimisticAssumptions);
+    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
+        this(null, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI, allowAssumptions);
     }
 
-    /**
-     * @param allowOptimisticAssumptions specifies whether {@link OptimisticAssumption}s can be made
-     *            while processing the graph
-     */
-    public StructuredGraph(ResolvedJavaMethod method, int entryBCI, boolean allowOptimisticAssumptions) {
-        this(null, method, uniqueGraphIds.incrementAndGet(), entryBCI, null, allowOptimisticAssumptions);
+    public StructuredGraph(ResolvedJavaMethod method, int entryBCI, AllowAssumptions allowAssumptions) {
+        this(null, method, uniqueGraphIds.incrementAndGet(), entryBCI, allowAssumptions);
     }
 
-    private StructuredGraph(String name, ResolvedJavaMethod method, long graphId, int entryBCI, Assumptions assumptions, boolean allowOptimisticAssumptions) {
+    private StructuredGraph(String name, ResolvedJavaMethod method, long graphId, int entryBCI, AllowAssumptions allowAssumptions) {
         super(name);
         this.setStart(add(new StartNode()));
         this.method = method;
         this.graphId = graphId;
         this.entryBCI = entryBCI;
-        this.assumptions = assumptions == null ? new Assumptions(allowOptimisticAssumptions) : assumptions;
+        this.assumptions = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null;
     }
 
     public Stamp getReturnStamp() {
@@ -218,9 +220,17 @@
     }
 
     public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod) {
-        final boolean ignored = true;
-        StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI, assumptions, ignored);
-        assert copy.assumptions.equals(assumptions);
+        return copy(newName, newMethod, AllowAssumptions.from(assumptions != null));
+    }
+
+    public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod, AllowAssumptions allowAssumptions) {
+        StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI, allowAssumptions);
+        if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
+            copy.assumptions.record(assumptions);
+        }
+        if (!isMethodRecordingEnabled()) {
+            copy.disableMethodRecording();
+        }
         copy.setGuardsStage(getGuardsStage());
         copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase;
         copy.hasValueProxies = hasValueProxies;
@@ -492,7 +502,36 @@
         hasValueProxies = state;
     }
 
+    /**
+     * Gets the object for recording assumptions while constructing of this graph.
+     *
+     * @return {@code null} if assumptions cannot be made for this graph
+     */
     public Assumptions getAssumptions() {
         return assumptions;
     }
+
+    /**
+     * Disables recording of method used while constructing this graph. This can be done at most
+     * once and must be done before any methods are recorded.
+     */
+    public void disableMethodRecording() {
+        assert methods != null : "cannot disable method recording more than once";
+        assert methods.isEmpty() : "cannot disable method recording once methods have been recorded";
+        methods = null;
+    }
+
+    public boolean isMethodRecordingEnabled() {
+        return methods != null;
+    }
+
+    /**
+     * Gets the methods whose bytecodes are used while constructing this graph.
+     *
+     * @return {@code null} if method recording has been {@linkplain #disableMethodRecording()
+     *         disabled}
+     */
+    public Set<ResolvedJavaMethod> getMethods() {
+        return methods;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -73,7 +73,7 @@
             ResolvedJavaType exactType;
             if (objectStamp.isExactType()) {
                 exactType = objectStamp.type();
-            } else if (objectStamp.type() != null && graph().getAssumptions().useOptimisticAssumptions()) {
+            } else if (objectStamp.type() != null && graph().getAssumptions() != null) {
                 exactType = objectStamp.type().findUniqueConcreteSubtype();
                 if (exactType != null) {
                     graph().getAssumptions().recordConcreteSubtype(objectStamp.type(), exactType);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -70,7 +70,7 @@
                 return resolveExactMethod(tool, type);
             }
             Assumptions assumptions = graph().getAssumptions();
-            if (type != null && assumptions.useOptimisticAssumptions()) {
+            if (type != null && assumptions != null) {
                 ResolvedJavaMethod resolvedMethod = type.findUniqueConcreteMethod(method);
                 if (resolvedMethod != null && !type.isInterface() && method.getDeclaringClass().isAssignableFrom(type)) {
                     assumptions.recordConcreteMethod(method, type, resolvedMethod);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -159,7 +159,7 @@
         }
 
         Assumptions assumptions = graph().getAssumptions();
-        if (assumptions.useOptimisticAssumptions()) {
+        if (assumptions != null) {
             ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
             if (exactType != null && !exactType.equals(type)) {
                 // Propagate more precise type information to usages of the checkcast.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -79,7 +79,7 @@
                 return result;
             }
             Assumptions assumptions = graph().getAssumptions();
-            if (assumptions.useOptimisticAssumptions()) {
+            if (assumptions != null) {
                 ResolvedJavaType exact = stampType.findUniqueConcreteSubtype();
                 if (exact != null) {
                     result = checkInstanceOf(forValue, exact, objectStamp.nonNull(), true);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -124,7 +124,7 @@
                 return resolvedMethod;
             }
             Assumptions assumptions = receiver.graph().getAssumptions();
-            if (assumptions.useOptimisticAssumptions()) {
+            if (assumptions != null) {
                 ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
                 if (uniqueConcreteType != null) {
                     ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveConcreteMethod(targetMethod, contextType);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -67,7 +67,7 @@
         } else if (objectStamp.type() != null && !objectStamp.type().hasFinalizableSubclass()) {
             // if either the declared type of receiver or the holder
             // can be assumed to have no finalizers
-            if (assumptions.useOptimisticAssumptions()) {
+            if (assumptions != null) {
                 assumptions.recordNoFinalizableSubclassAssumption(objectStamp.type());
                 return false;
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Feb 12 04:01:46 2015 +0100
@@ -364,7 +364,14 @@
         GraphUtil.killCFG(invokeNode);
 
         // Copy assumptions from inlinee to caller
-        graph.getAssumptions().record(inlineGraph.getAssumptions());
+        Assumptions assumptions = graph.getAssumptions();
+        if (assumptions != null) {
+            if (inlineGraph.getAssumptions() != null) {
+                assumptions.record(inlineGraph.getAssumptions());
+            }
+        } else {
+            assert inlineGraph.getAssumptions() == null : "cannot inline graph which makes assumptions into a graph that doesn't: " + inlineGraph + " -> " + graph;
+        }
 
         return duplicates;
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,15 +24,13 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.common.inlining.InliningUtil;
-import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
-import com.oracle.graal.phases.tiers.HighTierContext;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.common.inlining.info.elem.*;
+import com.oracle.graal.phases.tiers.*;
 
 public abstract class AbstractInlineInfo implements InlineInfo {
 
@@ -67,7 +65,10 @@
         }
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
-        invoke.asNode().graph().getAssumptions().recordMethodContents(concrete);
+        StructuredGraph graph = invoke.asNode().graph();
+        if (graph.isMethodRecordingEnabled()) {
+            graph.getMethods().add(concrete);
+        }
         return canonicalizeNodes;
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Thu Feb 12 04:01:46 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.graph.*;
@@ -198,7 +199,7 @@
      * for cloning before modification.</p>
      */
     private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
-        StructuredGraph newGraph = new StructuredGraph(method, caller.getAssumptions().useOptimisticAssumptions());
+        StructuredGraph newGraph = new StructuredGraph(method, AllowAssumptions.from(caller.getAssumptions() != null));
         try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) {
             if (context.getGraphBuilderSuite() != null) {
                 context.getGraphBuilderSuite().apply(newGraph, context);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -193,7 +193,7 @@
             }
         }
 
-        if (callTarget.graph().getAssumptions().useOptimisticAssumptions()) {
+        if (callTarget.graph().getAssumptions() != null) {
             ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
             if (uniqueSubtype != null) {
                 ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveConcreteMethod(targetMethod, contextType);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,13 +22,12 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 
 import org.junit.*;
 
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -331,7 +330,7 @@
 
     @Test
     public void testCanonicalLength() {
-        StructuredGraph graph = parseEager("testCanonicalLengthSnippet", DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testCanonicalLengthSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
@@ -347,7 +346,7 @@
 
     @Test
     public void testCanonicalEqual() {
-        StructuredGraph graph = parseEager("testCanonicalEqualSnippet", DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testCanonicalEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
@@ -361,7 +360,7 @@
 
     @Test
     public void testVirtualEqual() {
-        StructuredGraph graph = parseEager("testVirtualEqualSnippet", DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testVirtualEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
@@ -379,7 +378,7 @@
 
     @Test
     public void testVirtualNotEqual() {
-        StructuredGraph graph = parseEager("testVirtualNotEqualSnippet", DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager("testVirtualNotEqualSnippet", AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -248,7 +247,7 @@
      * @return the returned value or null if {@code expectedClass} is not found in the graph.
      */
     private ValueNode parseAndInline(String name, Class<? extends ValueNode> expectedClass) {
-        StructuredGraph graph = parseEager(name, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
 
@@ -40,8 +41,8 @@
     }
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
-        StructuredGraph graph = super.parseEager(m, allowOptimisticAssumptions);
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        StructuredGraph graph = super.parseEager(m, allowAssumptions);
         int handlers = graph.getNodes().filter(ExceptionObjectNode.class).count();
         Assert.assertEquals(1, handlers);
         return graph;
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.lang.reflect.*;
 
 import org.junit.*;
@@ -34,6 +32,7 @@
 import com.oracle.graal.graph.Edges.Type;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.*;
@@ -55,7 +54,7 @@
 
     }
 
-    StructuredGraph graph = new StructuredGraph(DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+    StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO);
     TestNode node;
     ConstantNode i1;
     ConstantNode i2;
@@ -114,7 +113,7 @@
         }
 
         ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
-        StructuredGraph g = parseProfiled(javaMethod, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph g = parseProfiled(javaMethod, AllowAssumptions.NO);
         HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new InlineMethodSubstitutionsPolicy(), new CanonicalizerPhase(true)).apply(g, context);
         new CanonicalizerPhase(false).apply(g, context);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static org.junit.Assert.*;
 
 import java.lang.reflect.*;
@@ -35,6 +34,7 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -49,7 +49,7 @@
 
     protected StructuredGraph test(final String snippet) {
         try (Scope s = Debug.scope("MethodSubstitutionTest", getResolvedJavaMethod(snippet))) {
-            StructuredGraph graph = parseEager(snippet, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
             HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             Debug.dump(graph, "Graph");
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
@@ -53,49 +52,49 @@
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
         return installer.makeGraph(m, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
     public void testRead1() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "1", ALLOW_OPTIMISTIC_ASSUMPTIONS), kind, true, ID);
+            assertRead(parseEager("read" + kind.name() + "1", AllowAssumptions.YES), kind, true, ID);
         }
     }
 
     @Test
     public void testRead2() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "2", ALLOW_OPTIMISTIC_ASSUMPTIONS), kind, true, ID);
+            assertRead(parseEager("read" + kind.name() + "2", AllowAssumptions.YES), kind, true, ID);
         }
     }
 
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "3", ALLOW_OPTIMISTIC_ASSUMPTIONS), kind, true, LocationIdentity.ANY_LOCATION);
+            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
     @Test
     public void testWrite1() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "1", ALLOW_OPTIMISTIC_ASSUMPTIONS), true, ID);
+            assertWrite(parseEager("write" + kind.name() + "1", AllowAssumptions.YES), true, ID);
         }
     }
 
     @Test
     public void testWrite2() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "2", ALLOW_OPTIMISTIC_ASSUMPTIONS), true, ID);
+            assertWrite(parseEager("write" + kind.name() + "2", AllowAssumptions.YES), true, ID);
         }
     }
 
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "3", ALLOW_OPTIMISTIC_ASSUMPTIONS), true, LocationIdentity.ANY_LOCATION);
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION);
         }
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.replacements.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
@@ -59,49 +58,49 @@
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
         return installer.makeGraph(m, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
     public void testRead1() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "1", ALLOW_OPTIMISTIC_ASSUMPTIONS), kind, true, ID);
+            assertRead(parseEager("read" + kind.name() + "1", AllowAssumptions.YES), kind, true, ID);
         }
     }
 
     @Test
     public void testRead2() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "2", ALLOW_OPTIMISTIC_ASSUMPTIONS), kind, true, ID);
+            assertRead(parseEager("read" + kind.name() + "2", AllowAssumptions.YES), kind, true, ID);
         }
     }
 
     @Test
     public void testRead3() {
         for (Kind kind : KINDS) {
-            assertRead(parseEager("read" + kind.name() + "3", ALLOW_OPTIMISTIC_ASSUMPTIONS), kind, true, LocationIdentity.ANY_LOCATION);
+            assertRead(parseEager("read" + kind.name() + "3", AllowAssumptions.YES), kind, true, LocationIdentity.ANY_LOCATION);
         }
     }
 
     @Test
     public void testWrite1() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "1", ALLOW_OPTIMISTIC_ASSUMPTIONS), true, ID);
+            assertWrite(parseEager("write" + kind.name() + "1", AllowAssumptions.YES), true, ID);
         }
     }
 
     @Test
     public void testWrite2() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "2", ALLOW_OPTIMISTIC_ASSUMPTIONS), true, ID);
+            assertWrite(parseEager("write" + kind.name() + "2", AllowAssumptions.YES), true, ID);
         }
     }
 
     @Test
     public void testWrite3() {
         for (Kind kind : KINDS) {
-            assertWrite(parseEager("write" + kind.name() + "3", ALLOW_OPTIMISTIC_ASSUMPTIONS), true, LocationIdentity.ANY_LOCATION);
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION);
         }
     }
 
@@ -403,7 +402,7 @@
     private void assertNumWordCasts(String snippetName, int expectedWordCasts) {
         HighTierContext context = new HighTierContext(getProviders(), null, null, OptimisticOptimizations.ALL);
 
-        StructuredGraph graph = parseEager(snippetName, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = parseEager(snippetName, AllowAssumptions.YES);
         new CanonicalizerPhase(false).apply(graph, context);
         Assert.assertEquals(expectedWordCasts, graph.getNodes().filter(WordCastNode.class).count());
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
@@ -46,7 +47,7 @@
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m, boolean allowOptimisticAssumptions) {
+    protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
         return installer.makeGraph(m, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
@@ -48,6 +47,7 @@
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -609,7 +609,7 @@
         protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse) {
             // Replacements cannot have optimistic assumptions since they have
             // to be valid for the entire run of the VM.
-            final StructuredGraph graph = new StructuredGraph(methodToParse, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            final StructuredGraph graph = new StructuredGraph(methodToParse, AllowAssumptions.NO);
             try (Scope s = Debug.scope("buildInitialGraph", graph)) {
                 MetaAccessProvider metaAccess = replacements.providers.getMetaAccess();
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.debug.Debug.*;
@@ -50,6 +49,7 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -565,7 +565,7 @@
         PhaseContext phaseContext = new PhaseContext(providers);
 
         // Copy snippet graph, replacing constant parameters with given arguments
-        final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method(), DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method(), AllowAssumptions.NO);
         Map<Node, Node> nodeReplacements = Node.newIdentityMap();
         nodeReplacements.put(snippetGraph.start(), snippetCopy.start());
 
@@ -1246,7 +1246,7 @@
 
             // Inline the snippet nodes, replacing parameters with the given args in the process
             String name = snippet.name == null ? "{copy}" : snippet.name + "{copy}";
-            StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method(), DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph snippetCopy = new StructuredGraph(name, snippet.method(), AllowAssumptions.NO);
             StartNode entryPointNode = snippet.start();
             FixedNode firstCFGNode = entryPointNode.next();
             StructuredGraph replaceeGraph = replacee.graph();
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.truffle.hotspot;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.graph.util.CollectionsAccess.*;
@@ -48,6 +47,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.inlining.*;
@@ -179,7 +179,7 @@
         Suites suites = suitesProvider.createSuites();
         LIRSuites lirSuites = suitesProvider.createLIRSuites();
         removeInliningPhase(suites);
-        StructuredGraph graph = new StructuredGraph(javaMethod, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = new StructuredGraph(javaMethod, AllowAssumptions.NO);
         new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
         PhaseSuite<HighTierContext> graphBuilderSuite = getGraphBuilderSuite(suitesProvider);
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.truffle.test;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import org.junit.*;
 
 import com.oracle.graal.compiler.test.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
@@ -55,14 +54,14 @@
 
     protected OptimizedCallTarget compileHelper(String methodName, RootNode root, Object[] arguments) {
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
-        StructuredGraph actual = partialEval(compilable, arguments, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph actual = partialEval(compilable, arguments, AllowAssumptions.YES);
         truffleCompiler.compileMethodHelper(actual, methodName, null, getSpeculationLog(), compilable);
         return compilable;
     }
 
     protected OptimizedCallTarget assertPartialEvalEquals(String methodName, RootNode root, Object[] arguments) {
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
-        StructuredGraph actual = partialEval(compilable, arguments, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph actual = partialEval(compilable, arguments, AllowAssumptions.YES);
         truffleCompiler.compileMethodHelper(actual, methodName, null, getSpeculationLog(), compilable);
         removeFrameStates(actual);
         StructuredGraph expected = parseForComparison(methodName);
@@ -76,21 +75,21 @@
 
     protected void assertPartialEvalNoInvokes(RootNode root, Object[] arguments) {
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
-        StructuredGraph actual = partialEval(compilable, arguments, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph actual = partialEval(compilable, arguments, AllowAssumptions.YES);
         removeFrameStates(actual);
         for (MethodCallTargetNode node : actual.getNodes(MethodCallTargetNode.class)) {
             Assert.fail("Found invalid method call target node: " + node);
         }
     }
 
-    protected StructuredGraph partialEval(OptimizedCallTarget compilable, Object[] arguments, boolean allowOptimisticAssumptions) {
+    protected StructuredGraph partialEval(OptimizedCallTarget compilable, Object[] arguments, AllowAssumptions allowAssumptions) {
         // Executed AST so that all classes are loaded and initialized.
         compilable.call(arguments);
         compilable.call(arguments);
         compilable.call(arguments);
 
         try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) {
-            return truffleCompiler.getPartialEvaluator().createGraph(compilable, allowOptimisticAssumptions, null);
+            return truffleCompiler.getPartialEvaluator().createGraph(compilable, allowAssumptions, null);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -107,7 +106,7 @@
 
     protected StructuredGraph parseForComparison(final String methodName) {
         try (Scope s = Debug.scope("Truffle", new DebugDumpScope("Comparison: " + methodName))) {
-            StructuredGraph graph = parseEager(methodName, ALLOW_OPTIMISTIC_ASSUMPTIONS);
+            StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
             compile(graph.method(), graph);
             return graph;
         } catch (Throwable e) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Feb 12 04:01:46 2015 +0100
@@ -40,6 +40,7 @@
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
@@ -96,7 +97,7 @@
         }
     }
 
-    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, boolean allowOptimisticAssumptions, GraphBuilderPlugins graalPlugins) {
+    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions, GraphBuilderPlugins graalPlugins) {
         if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) {
             constantReceivers = new HashSet<>();
         }
@@ -107,7 +108,7 @@
             throw Debug.handle(e);
         }
 
-        final StructuredGraph graph = new StructuredGraph(callTarget.toString(), callRootMethod, allowOptimisticAssumptions);
+        final StructuredGraph graph = new StructuredGraph(callTarget.toString(), callRootMethod, allowAssumptions);
         assert graph != null : "no graph for root method";
 
         try (Scope s = Debug.scope("CreateGraph", graph); Indent indent = Debug.logAndIndent("createGraph %s", graph)) {
@@ -277,7 +278,7 @@
     }
 
     public StructuredGraph createInlineGraph(String name, StructuredGraph caller) {
-        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, caller.getAssumptions().useOptimisticAssumptions());
+        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod, AllowAssumptions.from(caller.getAssumptions() != null));
         new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.truffle;
 
-import static com.oracle.graal.api.code.Assumptions.*;
-
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -36,6 +34,7 @@
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
@@ -61,7 +60,7 @@
 
     private final HashMap<List<Object>, StructuredGraph> cache = new HashMap<>();
     private final HashMap<List<Object>, Long> lastUsed = new HashMap<>();
-    private final StructuredGraph markerGraph = new StructuredGraph(DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+    private final StructuredGraph markerGraph = new StructuredGraph(AllowAssumptions.NO);
 
     private final ResolvedJavaType stringBuilderClass;
     private final ResolvedJavaType runtimeExceptionClass;
@@ -120,7 +119,7 @@
             lookupExceedsMaxSize();
         }
 
-        StructuredGraph graph = new StructuredGraph(method, DONT_ALLOW_OPTIMISTIC_ASSUMPTIONS);
+        StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
         PhaseContext phaseContext = new PhaseContext(providers);
         try (Scope s = Debug.scope("TruffleCache", providers.getMetaAccess(), method)) {
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,14 +22,13 @@
  */
 package com.oracle.graal.truffle;
 
-import static com.oracle.graal.api.code.Assumptions.*;
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 
 import java.util.*;
 
+import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -43,6 +42,7 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -123,7 +123,7 @@
             GraphBuilderSuiteInfo info = createGraphBuilderSuite();
 
             try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
-                graph = partialEvaluator.createGraph(compilable, ALLOW_OPTIMISTIC_ASSUMPTIONS, info.plugins);
+                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES, info.plugins);
             }
 
             if (Thread.currentThread().isInterrupted()) {
@@ -166,6 +166,13 @@
 
         compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
 
+        if (graph.isMethodRecordingEnabled()) {
+            Set<ResolvedJavaMethod> methods = graph.getMethods();
+            result.setMethods(methods.toArray(new ResolvedJavaMethod[methods.size()]));
+        } else {
+            assert result.getMethods() == null;
+        }
+
         List<AssumptionValidAssumption> validAssumptions = new ArrayList<>();
         Set<Assumption> newAssumptions = new HashSet<>();
         for (Assumption assumption : graph.getAssumptions()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionValidAssumption.java	Thu Feb 12 04:01:46 2015 +0100
@@ -25,7 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.truffle.*;
 
-public final class AssumptionValidAssumption extends Assumptions.OptimisticAssumption {
+public final class AssumptionValidAssumption extends Assumptions.Assumption {
 
     private static final long serialVersionUID = 2010244979610891262L;
 
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,120 +22,236 @@
  */
 package com.oracle.truffle.api.dsl.test;
 
+import static com.oracle.truffle.api.dsl.test.TestHelper.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
 import org.junit.*;
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.DerivedAssumptionNodeFactory;
-import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.DerivedAssumptionRedeclaredNodeFactory;
-import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.MultipleAssumptionsNodeFactory;
-import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.SingleAssumptionNodeFactory;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.AssumptionArrayTestFactory;
+import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.CacheAssumptionTestFactory;
+import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.FieldTestFactory;
+import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.MethodTestFactory;
+import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.NodeFieldTest2Factory;
+import com.oracle.truffle.api.dsl.test.AssumptionsTestFactory.StaticFieldTestFactory;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
 
 public class AssumptionsTest {
 
     @Test
-    public void testSingleAssumption() {
+    public void testField() {
+        CallTarget root = createCallTarget(FieldTestFactory.getInstance());
+        FieldTest node = getNode(root);
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(42));
+        node.field.invalidate();
+        try {
+            root.call(45);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    static class FieldTest extends ValueNode {
+
+        protected final Assumption field = Truffle.getRuntime().createAssumption();
+
+        @Specialization(assumptions = "field")
+        static int do1(int value) {
+            return value;
+        }
+    }
+
+    @Test
+    public void testNodeField() {
         Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.createRoot(SingleAssumptionNodeFactory.getInstance(), assumption);
+        CallTarget root = createCallTarget(NodeFieldTest2Factory.getInstance(), assumption);
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(42));
+        assumption.invalidate();
+        try {
+            root.call(45);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    @NodeField(name = "field", type = Assumption.class)
+    static class NodeFieldTest2 extends ValueNode {
 
-        Assert.assertEquals(42, TestHelper.executeWith(root));
-        assumption.invalidate();
-        Assert.assertEquals("42", TestHelper.executeWith(root));
+        @Specialization(assumptions = "field")
+        static int do1(int value) {
+            return value;
+        }
+    }
+
+    @Test
+    public void testStaticField() {
+        CallTarget root = createCallTarget(StaticFieldTestFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(42));
+        StaticFieldTest.FIELD.invalidate();
+        try {
+            root.call(45);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    static class StaticFieldTest extends ValueNode {
+
+        static final Assumption FIELD = Truffle.getRuntime().createAssumption();
+
+        @Specialization(assumptions = "FIELD")
+        static int do1(int value) {
+            return value;
+        }
+    }
+
+    @Test
+    public void testMethod() {
+        CallTarget root = createCallTarget(MethodTestFactory.getInstance());
+        MethodTest node = getNode(root);
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(42));
+        node.hiddenAssumption.invalidate();
+        try {
+            root.call(45);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
     }
 
-    @NodeAssumptions("assumption")
-    abstract static class SingleAssumptionNode extends ValueNode {
+    @NodeChild
+    static class MethodTest extends ValueNode {
 
-        @Specialization(assumptions = "assumption")
-        int do2() {
-            return 42;
+        private final Assumption hiddenAssumption = Truffle.getRuntime().createAssumption();
+
+        @Specialization(assumptions = "getAssumption()")
+        static int do1(int value) {
+            return value;
         }
 
-        @Fallback
-        Object doFallBack() {
-            return "42";
+        Assumption getAssumption() {
+            return hiddenAssumption;
+        }
+    }
+
+    @Test
+    public void testCacheAssumption() {
+        CallTarget root = createCallTarget(CacheAssumptionTestFactory.getInstance());
+        CacheAssumptionTest node = getNode(root);
+        assertEquals("do1", root.call(42));
+        assertEquals("do1", root.call(43));
+        assertEquals("do1", root.call(44));
+        node.assumptions.get(42).invalidate();
+        node.assumptions.put(42, null); // clear 42
+        node.assumptions.get(43).invalidate();
+        node.assumptions.get(44).invalidate();
+        assertEquals("do1", root.call(42)); // recreates 42
+        assertEquals("do2", root.call(43)); // invalid 43 -> remove -> insert do2
+        assertEquals("do2", root.call(46)); // no more lines can be created.
+    }
+
+    @Test
+    public void testCacheAssumptionLimit() {
+        CallTarget root = createCallTarget(CacheAssumptionTestFactory.getInstance());
+        assertEquals("do1", root.call(42));
+        assertEquals("do1", root.call(43));
+        assertEquals("do1", root.call(44));
+        assertEquals("do2", root.call(45));
+        assertEquals("do1", root.call(43));
+        assertEquals("do1", root.call(44));
+    }
+
+    @NodeChild
+    @SuppressWarnings("unused")
+    static class CacheAssumptionTest extends ValueNode {
+
+        private final Map<Integer, Assumption> assumptions = new HashMap<>();
+
+        @Specialization(guards = "value == cachedValue", assumptions = "getAssumption(cachedValue)")
+        static String do1(int value, @Cached("value") int cachedValue) {
+            return "do1";
+        }
+
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+
+        Assumption getAssumption(int value) {
+            Assumption assumption = assumptions.get(value);
+            if (assumption == null) {
+                assumption = Truffle.getRuntime().createAssumption();
+                assumptions.put(value, assumption);
+            }
+            return assumption;
+        }
+    }
+
+    @Test
+    public void testAssumptionArrays() {
+        CallTarget root = createCallTarget(AssumptionArrayTestFactory.getInstance());
+        AssumptionArrayTest node = getNode(root);
+
+        Assumption a1 = Truffle.getRuntime().createAssumption();
+        Assumption a2 = Truffle.getRuntime().createAssumption();
+
+        node.assumptions = new Assumption[]{a1, a2};
+
+        assertEquals("do1", root.call(42));
+
+        a2.invalidate();
+
+        assertEquals("do2", root.call(42));
+    }
+
+    @NodeChild
+    @SuppressWarnings("unused")
+    static class AssumptionArrayTest extends ValueNode {
+
+        Assumption[] assumptions;
+
+        @Specialization(assumptions = "assumptions")
+        static String do1(int value) {
+            return "do1";
+        }
+
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
 
     }
 
-    @Test
-    public void testMultipleAssumption() {
-        Assumption assumption1 = Truffle.getRuntime().createAssumption();
-        Assumption assumption2 = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.createRoot(MultipleAssumptionsNodeFactory.getInstance(), assumption1, assumption2);
-
-        Assert.assertEquals(42, TestHelper.executeWith(root));
-        assumption2.invalidate();
-        Assert.assertEquals("41", TestHelper.executeWith(root));
-        assumption1.invalidate();
-        Assert.assertEquals("42", TestHelper.executeWith(root));
-    }
-
-    @NodeAssumptions({"assumption1", "assumption2"})
-    abstract static class MultipleAssumptionsNode extends ValueNode {
-
-        @Specialization(assumptions = {"assumption1", "assumption2"})
-        int doInt() {
-            return 42;
-        }
-
-        @Specialization(assumptions = "assumption1")
-        Object doObject() {
-            return "41";
-        }
-
-        @Fallback
-        Object doFallBack() {
-            return "42";
+    @NodeChild
+    static class ErrorIncompatibleReturnType extends ValueNode {
+        @ExpectError("Incompatible return type int. Assumptions must be assignable to Assumption or Assumption[].")
+        @Specialization(assumptions = "3")
+        static int do1(int value) {
+            return value;
         }
     }
 
-    @Test
-    public void testDerivedAssumption() {
-        Assumption additionalAssumption = Truffle.getRuntime().createAssumption();
-        Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.createRoot(DerivedAssumptionNodeFactory.getInstance(), assumption, additionalAssumption);
+    @NodeChild
+    static class ErrorBoundDynamicValue extends ValueNode {
 
-        Assert.assertEquals(42, TestHelper.executeWith(root));
-        assumption.invalidate();
-        Assert.assertEquals(43, TestHelper.executeWith(root));
-        additionalAssumption.invalidate();
-        Assert.assertEquals("42", TestHelper.executeWith(root));
-    }
-
-    @NodeAssumptions({"additionalAssumption"})
-    abstract static class DerivedAssumptionNode extends SingleAssumptionNode {
-
-        @Specialization(assumptions = "additionalAssumption")
-        int doIntDerived() {
-            return 43;
+        @ExpectError("Assumption expressions must not bind dynamic parameter values.")
+        @Specialization(assumptions = "createAssumption(value)")
+        static int do1(int value) {
+            return value;
         }
 
-    }
-
-    @Test
-    public void testDerivedAssumptionRedeclared() {
-        Assumption additionalAssumption = Truffle.getRuntime().createAssumption();
-        Assumption assumption = Truffle.getRuntime().createAssumption();
-        TestRootNode<?> root = TestHelper.createRoot(DerivedAssumptionRedeclaredNodeFactory.getInstance(), additionalAssumption, assumption);
-
-        Assert.assertEquals(42, TestHelper.executeWith(root));
-        assumption.invalidate();
-        Assert.assertEquals(43, TestHelper.executeWith(root));
-        additionalAssumption.invalidate();
-        Assert.assertEquals("42", TestHelper.executeWith(root));
-    }
-
-    @NodeAssumptions({"additionalAssumption", "assumption"})
-    abstract static class DerivedAssumptionRedeclaredNode extends SingleAssumptionNode {
-
-        @Specialization(assumptions = "additionalAssumption")
-        int doIntDerived() {
-            return 43;
+        Assumption createAssumption(int value) {
+            return Truffle.getRuntime().createAssumption(String.valueOf(value));
         }
-
     }
 
 }
--- /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/CachedTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,320 @@
+/*
+ * 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.CachedTestFactory.BoundCacheFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.BoundCacheOverflowFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestBoundCacheOverflowContainsFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheFieldFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheMethodFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestCacheNodeFieldFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestGuardWithCachedAndDynamicParameterFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestGuardWithJustCachedParameterFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.TestMultipleCachesFactory;
+import com.oracle.truffle.api.dsl.test.CachedTestFactory.UnboundCacheFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
+
+@SuppressWarnings("unused")
+public class CachedTest {
+
+    @Test
+    public void testUnboundCache() {
+        CallTarget root = createCallTarget(UnboundCacheFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(43));
+        assertEquals(42, root.call(44));
+    }
+
+    @NodeChild
+    static class UnboundCache extends ValueNode {
+        @Specialization
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+    }
+
+    @Test
+    public void testBoundCache() {
+        CallTarget root = createCallTarget(BoundCacheFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        assertEquals(44, root.call(44));
+        try {
+            root.call(45);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    static class BoundCache extends ValueNode {
+
+        @Specialization(guards = "value == cachedValue", limit = "3")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+
+    }
+
+    @Test
+    public void testBoundCacheOverflow() {
+        CallTarget root = createCallTarget(BoundCacheOverflowFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        assertEquals(-1, root.call(44));
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        assertEquals(-1, root.call(44));
+    }
+
+    @NodeChild
+    static class BoundCacheOverflow extends ValueNode {
+
+        @Specialization(guards = "value == cachedValue", limit = "2")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+
+        @Specialization
+        static int do2(int value) {
+            return -1;
+        }
+
+    }
+
+    @Test
+    public void testBoundCacheOverflowContains() {
+        CallTarget root = createCallTarget(TestBoundCacheOverflowContainsFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        assertEquals(-1, root.call(44));
+        assertEquals(-1, root.call(42));
+        assertEquals(-1, root.call(43));
+        assertEquals(-1, root.call(44));
+    }
+
+    @NodeChild
+    static class TestBoundCacheOverflowContains extends ValueNode {
+
+        @Specialization(guards = "value == cachedValue", limit = "2")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+
+        @Specialization(contains = "do1")
+        static int do2(int value) {
+            return -1;
+        }
+
+    }
+
+    @Test
+    public void testCacheField() {
+        CallTarget root = createCallTarget(TestCacheFieldFactory.getInstance());
+        assertEquals(3, root.call(42));
+        assertEquals(3, root.call(43));
+    }
+
+    @NodeChild
+    static class TestCacheField extends ValueNode {
+
+        protected int field = 3;
+
+        @Specialization()
+        static int do1(int value, @Cached("field") int cachedValue) {
+            return cachedValue;
+        }
+
+    }
+
+    @Test
+    public void testCacheNodeField() {
+        CallTarget root = createCallTarget(TestCacheNodeFieldFactory.getInstance(), 21);
+        assertEquals(21, root.call(42));
+        assertEquals(21, root.call(43));
+    }
+
+    @NodeChild
+    @NodeField(name = "field", type = int.class)
+    static class TestCacheNodeField extends ValueNode {
+
+        @Specialization
+        static int do1(int value, @Cached("field") int cachedValue) {
+            return cachedValue;
+        }
+
+    }
+
+    @Test
+    public void testCacheMethod() {
+        TestCacheMethod.invocations = 0;
+        CallTarget root = createCallTarget(TestCacheMethodFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(43));
+        assertEquals(42, root.call(44));
+        assertEquals(1, TestCacheMethod.invocations);
+    }
+
+    @NodeChild
+    static class TestCacheMethod extends ValueNode {
+
+        static int invocations = 0;
+
+        @Specialization
+        static int do1(int value, @Cached("someMethod(value)") int cachedValue) {
+            return cachedValue;
+        }
+
+        static int someMethod(int value) {
+            invocations++;
+            return value;
+        }
+
+    }
+
+    @Test
+    public void testGuardWithJustCachedParameter() {
+        TestGuardWithJustCachedParameter.invocations = 0;
+        CallTarget root = createCallTarget(TestGuardWithJustCachedParameterFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(43));
+        assertEquals(42, root.call(44));
+        // guards with just cached parameters are just invoked on the slow path
+        assertEquals(assertionsEnabled() ? 4 : 1, TestGuardWithJustCachedParameter.invocations);
+    }
+
+    @NodeChild
+    static class TestGuardWithJustCachedParameter extends ValueNode {
+
+        static int invocations = 0;
+
+        @Specialization(guards = "someMethod(cachedValue)")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+
+        static boolean someMethod(int value) {
+            invocations++;
+            return true;
+        }
+
+    }
+
+    @Test
+    public void testGuardWithCachedAndDynamicParameter() {
+        TestGuardWithCachedAndDynamicParameter.cachedMethodInvocations = 0;
+        TestGuardWithCachedAndDynamicParameter.dynamicMethodInvocations = 0;
+        CallTarget root = createCallTarget(TestGuardWithCachedAndDynamicParameterFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(42, root.call(43));
+        assertEquals(42, root.call(44));
+        // guards with just cached parameters are just invoked on the slow path
+        assertEquals(assertionsEnabled() ? 4 : 1, TestGuardWithCachedAndDynamicParameter.cachedMethodInvocations);
+        assertEquals(4, TestGuardWithCachedAndDynamicParameter.dynamicMethodInvocations);
+    }
+
+    @NodeChild
+    static class TestGuardWithCachedAndDynamicParameter extends ValueNode {
+
+        static int cachedMethodInvocations = 0;
+        static int dynamicMethodInvocations = 0;
+
+        @Specialization(guards = {"dynamicMethod(value)", "cachedMethod(cachedValue)"})
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+
+        static boolean cachedMethod(int value) {
+            cachedMethodInvocations++;
+            return true;
+        }
+
+        static boolean dynamicMethod(int value) {
+            dynamicMethodInvocations++;
+            return true;
+        }
+
+    }
+
+    @NodeChild
+    static class TestMultipleCaches extends ValueNode {
+
+        @Specialization
+        static int do1(int value, @Cached("value") int cachedValue1, @Cached("value") int cachedValue2) {
+            return cachedValue1 + cachedValue2;
+        }
+
+    }
+
+    @Test
+    public void testMultipleCaches() {
+        CallTarget root = createCallTarget(TestMultipleCachesFactory.getInstance());
+        assertEquals(42, root.call(21));
+        assertEquals(42, root.call(22));
+        assertEquals(42, root.call(23));
+    }
+
+    @NodeChild
+    static class CachedError1 extends ValueNode {
+        @Specialization
+        static int do1(int value, @ExpectError("Incompatible return type int. The expression type must be equal to the parameter type double.")//
+                        @Cached("value") double cachedValue) {
+            return value;
+        }
+    }
+
+    @NodeChild
+    static class CachedError2 extends ValueNode {
+
+        // caches are not allowed to make backward references
+
+        @Specialization
+        static int do1(int value,
+                        @ExpectError("The initializer expression of parameter 'cachedValue1' binds unitialized parameter 'cachedValue2. Reorder the parameters to resolve the problem.") @Cached("cachedValue2") int cachedValue1,
+                        @Cached("value") int cachedValue2) {
+            return cachedValue1 + cachedValue2;
+        }
+
+    }
+
+    @NodeChild
+    static class CachedError3 extends ValueNode {
+
+        // cyclic dependency between cached expressions
+        @Specialization
+        static int do1(int value,
+                        @ExpectError("The initializer expression of parameter 'cachedValue1' binds unitialized parameter 'cachedValue2. Reorder the parameters to resolve the problem.") @Cached("cachedValue2") int cachedValue1,
+                        @Cached("cachedValue1") int cachedValue2) {
+            return cachedValue1 + cachedValue2;
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CodeFormatTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CodeFormatTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -51,11 +51,11 @@
             return true;
         }
 
-        @Specialization(guards = {"guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1",
-                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2",
-                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1",
-                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2",
-                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1"})
+        @Specialization(guards = {"guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1()",
+                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2()",
+                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1()",
+                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName2()",
+                        "guardWithaReeeeeeeeaaaaaaaaaaalllllllllyyyyyyyyLLLLLLLLLLLLLoooooooonnnnnnngggggggName1()"})
         public int execute() {
             return 42;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -100,7 +100,7 @@
             return a == 0;
         }
 
-        @Specialization(guards = "isZero")
+        @Specialization(guards = "isZero(a)")
         int f1(int a) {
             return a + 1;
         }
@@ -142,17 +142,16 @@
             return a > 0;
         }
 
-        @Implies("isGreaterZero")
         static boolean isOne(int a) {
             return a == 1;
         }
 
-        @Specialization(guards = {"isOne"})
+        @Specialization(guards = {"isOne(a)"})
         int f1(int a) {
             return a + 1;
         }
 
-        @Specialization(contains = "f1", guards = {"isGreaterZero"})
+        @Specialization(contains = "f1", guards = {"isGreaterZero(a)"})
         int f2(int a) {
             if (a == 1) {
                 return 2;
@@ -190,21 +189,16 @@
     @NodeChild("a")
     abstract static class Contains4 extends ValueNode {
 
-        static boolean isGreaterEqualZero(int a) {
-            return a >= 0;
-        }
-
-        @Implies("isGreaterEqualZero")
         static boolean isOne(int a) {
             return a == 1;
         }
 
-        @Specialization(guards = {"isOne"})
+        @Specialization(guards = "isOne(a)")
         int f0(int a) {
             return 1;
         }
 
-        @Specialization(contains = "f0", guards = {"isGreaterEqualZero"})
+        @Specialization(contains = "f0", guards = "a >= 0")
         int f1(int a) {
             return a;
         }
@@ -329,7 +323,7 @@
             return a;
         }
 
-        @ExpectError({"Specialization is not reachable. It is shadowed by f0(double).", "The contained specialization 'f0' is not fully compatible.%"})
+        @ExpectError({"Specialization is not reachable. It is shadowed by f0(double)."})
         @Specialization(contains = "f0")
         int f1(int a) { // implicit type
             return a;
@@ -343,7 +337,6 @@
             return a;
         }
 
-        @ExpectError("The contained specialization 'f0' is not fully compatible.%")
         @Specialization(contains = "f0")
         Object f1(int a, Object b) {
             return a;
@@ -357,7 +350,6 @@
             return a;
         }
 
-        @ExpectError("The contained specialization 'f0' is not fully compatible.%")
         @Specialization(contains = "f0")
         Object f1(int a, double b) { // implicit type
             return a;
@@ -370,7 +362,7 @@
             return true;
         }
 
-        @Specialization(guards = "g1")
+        @Specialization(guards = "g1()")
         Object f0() {
             return null;
         }
@@ -392,8 +384,8 @@
             return null;
         }
 
-        @ExpectError({"Specialization is not reachable. It is shadowed by f0().", "The contained specialization 'f0' is not fully compatible.%"})
-        @Specialization(guards = "g1", contains = "f0")
+        @ExpectError({"Specialization is not reachable. It is shadowed by f0()."})
+        @Specialization(guards = "g1()", contains = "f0")
         Object f1() {
             return null;
         }
@@ -405,13 +397,12 @@
             return true;
         }
 
-        @Specialization(guards = "g1")
+        @Specialization(guards = "g1()")
         Object f0() {
             return null;
         }
 
-        @ExpectError({"The contained specialization 'f0' is not fully compatible.%"})
-        @Specialization(guards = "!g1", contains = "f0")
+        @Specialization(guards = "!g1()", contains = "f0")
         Object f1() {
             return null;
         }
@@ -427,13 +418,12 @@
             return true;
         }
 
-        @Specialization(guards = "g1")
+        @Specialization(guards = "g1()")
         Object f0() {
             return null;
         }
 
-        @ExpectError({"The contained specialization 'f0' is not fully compatible.%"})
-        @Specialization(guards = "g2", contains = "f0")
+        @Specialization(guards = "g2()", contains = "f0")
         Object f1() {
             return null;
         }
@@ -441,7 +431,6 @@
 
     abstract static class ContainsGuard5 extends ValueNode {
 
-        @Implies("g2")
         boolean g1() {
             return true;
         }
@@ -450,12 +439,12 @@
             return true;
         }
 
-        @Specialization(guards = "g1")
+        @Specialization(guards = "g1()")
         Object f0() {
             return null;
         }
 
-        @Specialization(guards = "g2", contains = "f0")
+        @Specialization(guards = "g2()", contains = "f0")
         Object f1() {
             return null;
         }
@@ -463,7 +452,6 @@
 
     abstract static class ContainsGuard6 extends ValueNode {
 
-        @Implies("!g2")
         boolean g1() {
             return true;
         }
@@ -472,12 +460,12 @@
             return true;
         }
 
-        @Specialization(guards = "g1")
+        @Specialization(guards = "g1()")
         Object f0() {
             return null;
         }
 
-        @Specialization(guards = "!g2", contains = "f0")
+        @Specialization(guards = "!g2()", contains = "f0")
         Object f1() {
             return null;
         }
@@ -493,84 +481,12 @@
             return true;
         }
 
-        @Specialization(guards = {"g1", "g2"})
-        Object f0() {
-            return null;
-        }
-
-        @Specialization(guards = "g2", contains = "f0")
-        Object f1() {
-            return null;
-        }
-    }
-
-    @NodeAssumptions("a1")
-    abstract static class ContainsAssumption1 extends ValueNode {
-
-        @Specialization(assumptions = "a1")
-        Object f0() {
-            return null;
-        }
-
-        @Specialization(contains = "f0")
-        Object f1() {
-            return null;
-        }
-    }
-
-    @NodeAssumptions("a1")
-    abstract static class ContainsAssumption2 extends ValueNode {
-
-        @Specialization
+        @Specialization(guards = {"g1()", "g2()"})
         Object f0() {
             return null;
         }
 
-        @ExpectError({"Specialization is not reachable. It is shadowed by f0().", "The contained specialization 'f0' is not fully compatible.%"})
-        @Specialization(contains = "f0", assumptions = "a1")
-        Object f1() {
-            return null;
-        }
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    abstract static class ContainsAssumption3 extends ValueNode {
-
-        @Specialization(assumptions = "a1")
-        Object f0() {
-            return null;
-        }
-
-        @ExpectError({"The contained specialization 'f0' is not fully compatible.%"})
-        @Specialization(contains = "f0", assumptions = "a2")
-        Object f1() {
-            return null;
-        }
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    abstract static class ContainsAssumption4 extends ValueNode {
-
-        @Specialization(assumptions = {"a1", "a2"})
-        Object f0() {
-            return null;
-        }
-
-        @Specialization(contains = "f0", assumptions = "a1")
-        Object f1() {
-            return null;
-        }
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    abstract static class ContainsAssumption5 extends ValueNode {
-
-        @Specialization(assumptions = {"a2", "a1"})
-        Object f0() {
-            return null;
-        }
-
-        @Specialization(contains = "f0", assumptions = "a1")
+        @Specialization(guards = "g2()", contains = "f0")
         Object f1() {
             return null;
         }
@@ -619,20 +535,12 @@
     @NodeChild("a")
     static class PolymorphicToMonomorphic0 extends ValueNode {
 
-        boolean isOne(int a) {
-            return a == 1;
-        }
-
-        boolean isTwo(int a) {
-            return a == 2;
-        }
-
-        @Specialization(guards = "isOne")
+        @Specialization(guards = "a == 1")
         int do1(int a) {
             return a;
         }
 
-        @Specialization(guards = "isTwo")
+        @Specialization(guards = "a == 2")
         int do2(int a) {
             return a;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -35,7 +35,8 @@
 import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs3Factory;
 import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs4Factory;
 import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs5Factory;
-import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluated1NodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluated2NodeFactory;
 import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode;
@@ -79,12 +80,12 @@
     }
 
     @Test
-    public void testDoubleEvaluated() {
+    public void testDoubleEvaluated1() {
         ArgumentNode arg0 = new ArgumentNode(0);
         ArgumentNode arg1 = new ArgumentNode(1);
-        CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluatedNodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null)));
+        CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluated1NodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null)));
 
-        Assert.assertEquals(85, callTarget.call(new Object[]{42, 43}));
+        Assert.assertEquals(42, callTarget.call(new Object[]{43, 1}));
         Assert.assertEquals(1, arg0.getInvocationCount());
         Assert.assertEquals(1, arg1.getInvocationCount());
     }
@@ -94,7 +95,7 @@
 
         @Specialization
         int doExecuteWith(int exp0, int exp1) {
-            return exp0 + exp1;
+            return exp0 - exp1;
         }
 
         public abstract Object executeEvaluated(VirtualFrame frame, Object exp0, Object exp1);
@@ -103,11 +104,32 @@
     }
 
     @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1"), @NodeChild(value = "exp2", type = DoubleEvaluatedNode.class, executeWith = {"exp0", "exp1"})})
-    abstract static class UseDoubleEvaluatedNode extends ValueNode {
+    abstract static class UseDoubleEvaluated1Node extends ValueNode {
 
         @Specialization
         int call(int exp0, int exp1, int exp2) {
-            Assert.assertEquals(exp0 + exp1, exp2);
+            Assert.assertEquals(exp0 - exp1, exp2);
+            return exp2;
+        }
+    }
+
+    @Test
+    public void testDoubleEvaluated2() {
+        ArgumentNode arg0 = new ArgumentNode(0);
+        ArgumentNode arg1 = new ArgumentNode(1);
+        CallTarget callTarget = TestHelper.createCallTarget(UseDoubleEvaluated2NodeFactory.create(arg0, arg1, DoubleEvaluatedNodeFactory.create(null, null)));
+
+        Assert.assertEquals(42, callTarget.call(new Object[]{1, 43}));
+        Assert.assertEquals(1, arg0.getInvocationCount());
+        Assert.assertEquals(1, arg1.getInvocationCount());
+    }
+
+    @NodeChildren({@NodeChild("exp0"), @NodeChild("exp1"), @NodeChild(value = "exp2", type = DoubleEvaluatedNode.class, executeWith = {"exp1", "exp0"})})
+    abstract static class UseDoubleEvaluated2Node extends ValueNode {
+
+        @Specialization
+        int call(int exp0, int exp1, int exp2) {
+            Assert.assertEquals(exp1 - exp0, exp2);
             return exp2;
         }
     }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -319,7 +319,6 @@
 
     @TypeSystemReference(ExecuteMethodTypes.class)
     @NodeChild(value = "a", type = ChildNoFrame.class)
-    @ExpectError("Invalid inconsistent frame types [MaterializedFrame, void] found for the declared execute methods.%")
     abstract static class ExecuteWithFrameError5 extends Node {
 
         abstract Object execute();
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -104,7 +104,7 @@
             return "(int)";
         }
 
-        @Specialization(guards = "notInt")
+        @Specialization(guards = "notInt(a)")
         String f2(Object a) {
             return "(object)";
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -32,40 +32,40 @@
 
 public class ImportGuardsTest {
 
-    @ImportGuards(Imports0.class)
+    @ImportStatic(Imports0.class)
     @NodeChild("a")
     static class ImportGuards0 extends ValueNode {
 
-        @Specialization(guards = "staticGuard")
+        @Specialization(guards = "staticGuard(a)")
         int f0(int a) {
             return a;
         }
     }
 
     @NodeChild("a")
-    @ImportGuards(Imports0.class)
+    @ImportStatic(Imports0.class)
     static class ImportGuards1 extends ValueNode {
 
-        @ExpectError("No compatible guard with method name 'nonStaticGuard' found.")
-        @Specialization(guards = "nonStaticGuard")
+        @ExpectError("Error parsing expression 'nonStaticGuard(a)': The method nonStaticGuard is undefined for the enclosing scope.")
+        @Specialization(guards = "nonStaticGuard(a)")
         int f1(int a) {
             return a;
         }
 
-        @ExpectError("No compatible guard with method name 'protectedGuard' found.")
-        @Specialization(guards = "protectedGuard")
+        @ExpectError("Error parsing expression 'protectedGuard(a)': The method protectedGuard is undefined for the enclosing scope.")
+        @Specialization(guards = "protectedGuard(a)")
         int f2(int a) {
             return a;
         }
 
-        @ExpectError("No compatible guard with method name 'packageGuard' found.")
-        @Specialization(guards = "packageGuard")
+        @ExpectError("Error parsing expression 'packageGuard(a)': The method packageGuard is undefined for the enclosing scope.")
+        @Specialization(guards = "packageGuard(a)")
         int f3(int a) {
             return a;
         }
 
-        @ExpectError("No compatible guard with method name 'privateGuard' found.")
-        @Specialization(guards = "privateGuard")
+        @ExpectError("Error parsing expression 'privateGuard(a)': The method privateGuard is undefined for the enclosing scope.")
+        @Specialization(guards = "privateGuard(a)")
         int f4(int a) {
             return a;
         }
@@ -97,7 +97,7 @@
 
     @ExpectError("The specified import guard class 'com.oracle.truffle.api.dsl.test.ImportGuardsTest.Imports1' must be public.")
     @NodeChild("a")
-    @ImportGuards(Imports1.class)
+    @ImportStatic(Imports1.class)
     static class ImportGuards2 extends ValueNode {
 
         int do1(int a) {
@@ -111,7 +111,7 @@
 
     @ExpectError("The specified import guard class 'com.oracle.truffle.api.dsl.test.ImportGuardsTest.Imports2' must be public.")
     @NodeChild("a")
-    @ImportGuards(Imports2.class)
+    @ImportStatic(Imports2.class)
     static class ImportGuards3 extends ValueNode {
 
         int do1(int a) {
@@ -121,7 +121,7 @@
 
     @ExpectError("The specified import guard class 'boolean' is not a declared type.")
     @NodeChild("a")
-    @ImportGuards(boolean.class)
+    @ImportStatic(boolean.class)
     static class ImportGuards4 extends ValueNode {
 
         int do1(int a) {
@@ -135,7 +135,7 @@
 
     @ExpectError("At least import guard classes must be specified.")
     @NodeChild("a")
-    @ImportGuards({})
+    @ImportStatic({})
     static class ImportGuards5 extends ValueNode {
 
         int do1(int a) {
@@ -151,7 +151,7 @@
                         array(1, 1));
     }
 
-    @ImportGuards(Imports0.class)
+    @ImportStatic(Imports0.class)
     @NodeChild("a")
     static class ImportGuards6 extends ValueNode {
 
@@ -159,7 +159,7 @@
             return a == 1;
         }
 
-        @Specialization(guards = "staticGuard")
+        @Specialization(guards = "staticGuard(a)")
         int f0(int a) {
             return a;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/InsertBeforeTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/InsertBeforeTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -30,20 +30,12 @@
     @NodeChild("a")
     static class InsertBefore1Base extends ValueNode {
 
-        boolean g1(int a) {
-            return a == 1;
-        }
-
-        boolean g2(int a) {
-            return a == 2;
-        }
-
-        @Specialization(guards = "g1")
+        @Specialization(guards = "a == 1")
         int f1(int a) {
             return a;
         }
 
-        @Specialization(guards = "g2")
+        @Specialization(guards = "a == 2")
         int f3(int a) {
             return a;
         }
@@ -63,11 +55,7 @@
     @NodeChild("a")
     static class InsertBefore1T2 extends InsertBefore1Base {
 
-        boolean g0(int a) {
-            return a == 0;
-        }
-
-        @Specialization(guards = "g0", insertBefore = "f1")
+        @Specialization(guards = "a == 0", insertBefore = "f1")
         int f0(int a) {
             return a;
         }
@@ -77,11 +65,7 @@
     @NodeChild("a")
     static class InsertBefore1T3 extends InsertBefore1Base {
 
-        boolean g0(int a) {
-            return a == 0;
-        }
-
-        @Specialization(guards = "g0", insertBefore = "f3")
+        @Specialization(guards = "a == 0", insertBefore = "f3")
         int f0(int a) {
             return a;
         }
@@ -93,10 +77,6 @@
                     "Method f1(int) at annotation @Specialization is erroneous: Specialization is not reachable. It is shadowed by f0(int)."})
     static class InsertBefore1T4 extends InsertBefore1Base {
 
-        boolean g0(int a) {
-            return a == 0;
-        }
-
         @Specialization(insertBefore = "f1")
         int f0(int a) {
             return a;
@@ -126,7 +106,7 @@
             return a == 0;
         }
 
-        @Specialization(insertBefore = "f1", guards = "g0")
+        @Specialization(insertBefore = "f1", guards = "a == 0")
         int f0(int a) {
             return a;
         }
@@ -136,11 +116,7 @@
     @NodeChild("a")
     static class InsertBefore1T6part2 extends InsertBefore1T6part1 {
 
-        boolean g(int a) {
-            return a == 0;
-        }
-
-        @Specialization(insertBefore = "f0", guards = "g")
+        @Specialization(insertBefore = "f0", guards = "a == 3")
         int f(int a) {
             return a;
         }
--- /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/LimitTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,171 @@
+/*
+ * 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.LimitTestFactory.ConstantLimitTestFactory;
+import com.oracle.truffle.api.dsl.test.LimitTestFactory.DefaultLimit3TestFactory;
+import com.oracle.truffle.api.dsl.test.LimitTestFactory.LocalLimitTestFactory;
+import com.oracle.truffle.api.dsl.test.LimitTestFactory.MethodLimitTestFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
+
+@SuppressWarnings("unused")
+public class LimitTest {
+
+    @Test
+    public void testDefaultLimit3() {
+        CallTarget root = createCallTarget(DefaultLimit3TestFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        assertEquals(44, root.call(44));
+        try {
+            root.call(45);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    static class DefaultLimit3Test extends ValueNode {
+        @Specialization(guards = "value == cachedValue")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+    }
+
+    @Test
+    public void testConstantLimit() {
+        CallTarget root = createCallTarget(ConstantLimitTestFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        try {
+            root.call(44);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    static class ConstantLimitTest extends ValueNode {
+
+        public static final int LIMIT = 2;
+
+        @Specialization(limit = "LIMIT", guards = "value == cachedValue")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+    }
+
+    @Test
+    public void testLocalLimit() {
+        CallTarget root = createCallTarget(LocalLimitTestFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        try {
+            root.call(44);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+    }
+
+    @NodeChild
+    static class LocalLimitTest extends ValueNode {
+
+        protected int localLimit = 2;
+
+        @Specialization(limit = "localLimit", guards = "value == cachedValue")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+    }
+
+    @Test
+    public void testMethodLimit() {
+        MethodLimitTest.invocations = 0;
+        CallTarget root = createCallTarget(MethodLimitTestFactory.getInstance());
+        assertEquals(42, root.call(42));
+        assertEquals(43, root.call(43));
+        try {
+            root.call(44);
+            fail();
+        } catch (UnsupportedSpecializationException e) {
+        }
+        assertEquals(3, MethodLimitTest.invocations);
+    }
+
+    @NodeChild
+    static class MethodLimitTest extends ValueNode {
+
+        static int invocations = 0;
+
+        @Specialization(limit = "calculateLimitFor(cachedValue, invocations)", guards = "value == cachedValue")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return cachedValue;
+        }
+
+        int calculateLimitFor(int cachedValue, int boundField) {
+            invocations = boundField + 1;
+            return 2;
+        }
+
+    }
+
+    @NodeChild
+    static class LimitErrorTest1 extends ValueNode {
+        @ExpectError("The limit expression has no effect.%")
+        @Specialization(limit = "4")
+        static int do1(int value) {
+            return value;
+        }
+    }
+
+    @NodeChild
+    static class LimitErrorTest2 extends ValueNode {
+        public static final Object CONSTANT = new Object();
+
+        @ExpectError("Incompatible return type Object. Limit expressions must return int.")
+        @Specialization(limit = "CONSTANT", guards = "value == cachedValue")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return value;
+        }
+    }
+
+    @NodeChild
+    static class LimitErrorTest3 extends ValueNode {
+
+        public static final Object CONSTANT = new Object();
+
+        @ExpectError("Limit expressions must not bind dynamic parameter values.")
+        @Specialization(limit = "value", guards = "value == cachedValue")
+        static int do1(int value, @Cached("value") int cachedValue) {
+            return value;
+        }
+    }
+
+}
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -27,296 +27,473 @@
 
 import org.junit.*;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.Guard1Factory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.Guard2Factory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardWithBaseClassFactory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardWithBoxedPrimitiveFactory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardWithObjectFactory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestAbstractGuard1Factory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestGuardResolve1Factory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestGuardResolve2Factory;
-import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.TestGuardResolve3Factory;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.Abstract;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.BExtendsAbstract;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.CExtendsAbstract;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.Interface;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.dsl.test.LimitTestFactory.ConstantLimitTestFactory;
+import com.oracle.truffle.api.dsl.test.LimitTestFactory.LocalLimitTestFactory;
+import com.oracle.truffle.api.dsl.test.LimitTestFactory.MethodLimitTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardCompareWithFieldTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardComplexTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardEqualTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardFieldTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardGreaterEqualTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardGreaterTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardLessEqualTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardLessTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardMethodTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardMultipleAndMethodTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardMultipleOrMethodTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardNotTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardOrTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardStaticFieldTestFactory;
+import com.oracle.truffle.api.dsl.test.MethodGuardsTestFactory.GuardUnboundMethodTestFactory;
 import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
 
 @SuppressWarnings("unused")
 public class MethodGuardsTest {
 
-    private static final Object NULL = new Object();
+    @Test
+    public void testGuardEqual() {
+        CallTarget root = createCallTarget(GuardEqualTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(2));
+        assertEquals("do1", root.call(1));
+    }
+
+    @NodeChild
+    static class GuardEqualTest extends ValueNode {
+        @Specialization(guards = "value == 1")
+        static String do1(int value) {
+            return "do1";
+        }
+
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+    }
 
     @Test
-    public void testInvocations() {
-        TestRootNode<Guard1> root = createRoot(Guard1Factory.getInstance());
-
-        assertEquals(Integer.MAX_VALUE, executeWith(root, Integer.MAX_VALUE - 1));
-        assertEquals(1, Guard1.specializedInvocations);
-        assertEquals(0, Guard1.genericInvocations);
-
-        assertEquals(42, executeWith(root, Integer.MAX_VALUE));
-        assertEquals(1, Guard1.specializedInvocations);
-        assertEquals(1, Guard1.genericInvocations);
+    public void testGuardLessEqual() {
+        CallTarget root = createCallTarget(GuardLessEqualTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(0));
+        assertEquals("do2", root.call(2));
+        assertEquals("do1", root.call(0));
     }
 
     @NodeChild
-    static class Guard1 extends ValueNode {
-
-        static int specializedInvocations = 0;
-        static int genericInvocations = 0;
-
-        boolean g(int value0) {
-            return value0 != Integer.MAX_VALUE;
+    static class GuardLessEqualTest extends ValueNode {
+        @Specialization(guards = "value <= 1")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "g")
-        int f1(int value0) {
-            specializedInvocations++;
-            return value0 + 1;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+    }
+
+    @Test
+    public void testGuardLess() {
+        CallTarget root = createCallTarget(GuardLessTestFactory.getInstance());
+        assertEquals("do1", root.call(0));
+        assertEquals("do2", root.call(1));
+        assertEquals("do2", root.call(2));
+        assertEquals("do1", root.call(-1));
+    }
+
+    @NodeChild
+    static class GuardLessTest extends ValueNode {
+        @Specialization(guards = "value < 1")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Fallback
-        int f2(Object value0) {
-            genericInvocations++;
-            return 42;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+    }
+
+    @Test
+    public void testGuardGreaterEqual() {
+        CallTarget root = createCallTarget(GuardGreaterEqualTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(0));
+        assertEquals("do1", root.call(2));
+        assertEquals("do2", root.call(0));
+    }
+
+    @NodeChild
+    static class GuardGreaterEqualTest extends ValueNode {
+        @Specialization(guards = "value >= 1")
+        static String do1(int value) {
+            return "do1";
+        }
+
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
     }
 
     @Test
-    public void testGuardSideEffect() {
-        TestRootNode<Guard2> root = createRoot(Guard2Factory.getInstance());
-
-        assertEquals(42, executeWith(root, NULL));
-
-        Guard2.globalFlag = true;
-        assertEquals(41, executeWith(root, NULL));
-
-        Guard2.globalFlag = false;
-        assertEquals(42, executeWith(root, NULL));
+    public void testGuardGreater() {
+        CallTarget root = createCallTarget(GuardGreaterTestFactory.getInstance());
+        assertEquals("do1", root.call(2));
+        assertEquals("do2", root.call(0));
+        assertEquals("do2", root.call(1));
+        assertEquals("do2", root.call(0));
     }
 
     @NodeChild
-    static class Guard2 extends ValueNode {
-
-        static boolean globalFlag = false;
-
-        static boolean globalFlagGuard() {
-            return globalFlag;
+    static class GuardGreaterTest extends ValueNode {
+        @Specialization(guards = "value > 1")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "globalFlagGuard")
-        int f1(Object value0) {
-            return 41;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+    }
+
+    @Test
+    public void testGuardOr() {
+        CallTarget root = createCallTarget(GuardOrTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(0));
+        assertEquals("do2", root.call(2));
+        assertEquals("do2", root.call(-1));
+    }
+
+    @NodeChild
+    static class GuardOrTest extends ValueNode {
+        @Specialization(guards = "value == 1 || value == 0")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Fallback
-        int f2(Object value0) {
-            return 42; // the generic answer to all questions
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
     }
 
     @Test
-    public void testGuardWithBaseClass() {
-        TestRootNode<?> root = createRoot(GuardWithBaseClassFactory.getInstance());
-
-        assertEquals(42, executeWith(root, new BExtendsAbstract()));
+    public void testGuardNot() {
+        CallTarget root = createCallTarget(GuardNotTestFactory.getInstance());
+        assertEquals("do1", root.call(0));
+        assertEquals("do1", root.call(2));
+        assertEquals("do2", root.call(1));
+        assertEquals("do1", root.call(0));
     }
 
-    @NodeChild("expression")
-    public abstract static class GuardWithBaseClass extends ValueNode {
-
-        boolean baseGuard(Abstract base) {
-            return true;
+    @NodeChild
+    static class GuardNotTest extends ValueNode {
+        @Specialization(guards = "!(value == 1)")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "baseGuard")
-        int doSpecialized(BExtendsAbstract value0) {
-            return 42;
-        }
-    }
-
-    @NodeChild("expression")
-    public abstract static class GuardWithBaseInterface extends ValueNode {
-
-        boolean baseGuard(CharSequence base) {
-            return true;
-        }
-
-        @Specialization(guards = "baseGuard")
-        @ExpectError("No guard with name 'baseGuard' matched the required signature.%")
-        int doSpecialized(String value0) {
-            return 42;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
     }
 
     @Test
-    public void testGuardWithPrimitive() {
-        TestRootNode<?> root = createRoot(GuardWithBoxedPrimitiveFactory.getInstance());
+    public void testGuardField() {
+        CallTarget root = createCallTarget(GuardFieldTestFactory.getInstance());
+        GuardFieldTest node = getNode(root);
+        node.field = true;
+        assertEquals("do1", root.call(0));
+        assertEquals("do1", root.call(2));
 
-        assertEquals(42, executeWith(root, 42));
+        node.field = false;
+        try {
+            root.call(2);
+            fail("expected Assertion failed");
+        } catch (AssertionError e) {
+        }
     }
 
-    @NodeChild("expression")
-    public abstract static class GuardWithBoxedPrimitive extends ValueNode {
+    @NodeChild
+    static class GuardFieldTest extends ValueNode {
 
-        boolean baseGuard(Integer primitive) {
-            return true;
+        boolean field;
+
+        @Specialization(guards = "field")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "baseGuard")
-        int doSpecialized(int value0) {
-            return value0;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+    }
+
+    @Test
+    public void testGuardCompareWithField() {
+        CallTarget root = createCallTarget(GuardCompareWithFieldTestFactory.getInstance());
+        GuardCompareWithFieldTest node = getNode(root);
+        node.field = 1;
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(2));
+
+        node.field = 2;
+        assertEquals("do2", root.call(1));
+        assertEquals("do1", root.call(2));
+    }
+
+    @NodeChild
+    static class GuardCompareWithFieldTest extends ValueNode {
+
+        int field;
+
+        @Specialization(guards = "value == field")
+        static String do1(int value) {
+            return "do1";
+        }
+
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
     }
 
     @Test
-    public void testGuardWithObject() {
-        TestRootNode<?> root = createRoot(GuardWithObjectFactory.getInstance());
-
-        assertEquals(42, executeWith(root, 42));
+    public void testGuardStaticField() {
+        CallTarget root = createCallTarget(GuardStaticFieldTestFactory.getInstance());
+        GuardStaticFieldTest.field = true;
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(2));
+        GuardStaticFieldTest.field = false;
+        try {
+            root.call(2);
+            fail("expected Assertion failed");
+        } catch (AssertionError e) {
+        }
     }
 
-    @NodeChild("expression")
-    public abstract static class GuardWithObject extends ValueNode {
+    @NodeChild
+    static class GuardStaticFieldTest extends ValueNode {
 
-        boolean baseGuard(Object primitive) {
-            return true;
+        static boolean field;
+
+        @Specialization(guards = "field")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "baseGuard")
-        int doSpecialized(int value0) {
-            return value0;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
     }
 
     @Test
-    public void testGuardResolve1() {
-        TestRootNode<?> root = createRoot(TestGuardResolve1Factory.getInstance());
-
-        assertEquals(42, executeWith(root, 42));
+    public void testGuardMethod() {
+        CallTarget root = createCallTarget(GuardMethodTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(2));
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(0));
     }
 
-    @NodeChild("expression")
-    public abstract static class TestGuardResolve1 extends ValueNode {
+    @NodeChild
+    static class GuardMethodTest extends ValueNode {
 
-        boolean guard(Object primitive) {
-            return false;
+        @Specialization(guards = "method(value)")
+        static String do1(int value) {
+            return "do1";
         }
 
-        boolean guard(int primitive) {
-            return true;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
 
-        @Specialization(guards = "guard")
-        int doSpecialized(int value0) {
-            return value0;
+        boolean method(int value) {
+            return value == 1;
         }
     }
 
     @Test
-    public void testGuardResolve2() {
-        TestRootNode<?> root = createRoot(TestGuardResolve2Factory.getInstance());
-        assertEquals(42, executeWith(root, new BExtendsAbstract()));
+    public void testGuardUnboundMethodField() {
+        CallTarget root = createCallTarget(GuardUnboundMethodTestFactory.getInstance());
+        GuardUnboundMethodTest node = getNode(root);
+        node.hiddenValue = true;
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(2));
+        node.hiddenValue = false;
+        try {
+            root.call(2);
+            fail("expected Assertion failed");
+        } catch (AssertionError e) {
+        }
     }
 
-    @NodeChild("expression")
-    public abstract static class TestGuardResolve2 extends ValueNode {
+    @NodeChild
+    static class GuardUnboundMethodTest extends ValueNode {
 
-        boolean guard(Object primitive) {
-            return false;
+        private boolean hiddenValue;
+
+        @Specialization(guards = "method()")
+        static String do1(int value) {
+            return "do1";
         }
 
-        boolean guard(Abstract primitive) {
-            return true;
+        boolean method() {
+            return hiddenValue;
+        }
+    }
+
+    @Test
+    public void testStaticGuardMethod() {
+        CallTarget root = createCallTarget(GuardMethodTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(2));
+        assertEquals("do1", root.call(1));
+        assertEquals("do2", root.call(0));
+    }
+
+    @NodeChild
+    static class StaticGuardMethodTest extends ValueNode {
+
+        @Specialization(guards = "method(value)")
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "guard")
-        int doSpecialized(BExtendsAbstract value0) {
-            return 42;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+
+        static boolean method(int value) {
+            return value == 1;
         }
     }
 
     @Test
-    public void testGuardResolve3() {
-        TestRootNode<?> root = createRoot(TestGuardResolve3Factory.getInstance());
-
-        assertEquals(42, executeWith(root, new BExtendsAbstract()));
+    public void testMultipleGuardAndMethod() {
+        CallTarget root = createCallTarget(GuardMultipleAndMethodTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(2));
+        assertEquals("do2", root.call(3));
+        assertEquals("do2", root.call(0));
     }
 
-    @NodeChild("expression")
-    public abstract static class TestGuardResolve3 extends ValueNode {
-
-        boolean guard(Object primitive) {
-            return false;
-        }
+    @NodeChild
+    static class GuardMultipleAndMethodTest extends ValueNode {
 
-        boolean guard(Abstract primitive) {
-            return false;
-        }
-
-        boolean guard(BExtendsAbstract primitive) {
-            return true;
+        @Specialization(guards = {"method1(value)", "method2(value)"})
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "guard")
-        int doSpecialized(BExtendsAbstract value0) {
-            return 42;
-        }
-    }
-
-    @NodeChild("expression")
-    public abstract static class TestGuardResolve4 extends ValueNode {
-
-        boolean guard(Abstract primitive) {
-            return false;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
 
-        @Specialization(guards = "guard")
-        int doSpecialized(BExtendsAbstract value0) {
-            return 42;
-        }
-    }
-
-    @NodeChildren({@NodeChild("a"), @NodeChild("b")})
-    abstract static class TestGuardResolve5 extends ValueNode {
-
-        @Specialization(guards = "guard")
-        int add(Interface left, Interface right) {
-            return 42;
+        boolean method1(int value) {
+            return value >= 1;
         }
 
-        boolean guard(Interface left, Object right) {
-            return true;
+        boolean method2(int value) {
+            return value <= 2;
         }
     }
 
     @Test
-    public void testAbstractGuard1() {
-        TestRootNode<?> root = createRoot(TestAbstractGuard1Factory.getInstance());
-
-        assertEquals(BExtendsAbstract.INSTANCE, executeWith(root, BExtendsAbstract.INSTANCE));
-        assertEquals(CExtendsAbstract.INSTANCE, executeWith(root, CExtendsAbstract.INSTANCE));
+    public void testMultipleGuardOrMethod() {
+        CallTarget root = createCallTarget(GuardMultipleOrMethodTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(2));
+        assertEquals("do2", root.call(3));
+        assertEquals("do2", root.call(0));
     }
 
-    @NodeChild("expression")
-    public abstract static class TestAbstractGuard1 extends ValueNode {
+    @NodeChild
+    static class GuardMultipleOrMethodTest extends ValueNode {
 
-        boolean guard(Abstract value0) {
-            return true;
+        @Specialization(guards = {"method1(value) || method2(value)"})
+        static String do1(int value) {
+            return "do1";
         }
 
-        @Specialization(guards = "guard")
-        BExtendsAbstract do1(BExtendsAbstract value0) {
-            return value0;
+        @Specialization
+        static String do2(int value) {
+            return "do2";
         }
 
-        @Specialization(guards = "guard")
-        CExtendsAbstract do2(CExtendsAbstract value0) {
-            return value0;
+        boolean method1(int value) {
+            return value == 1;
+        }
+
+        boolean method2(int value) {
+            return value == 2;
         }
     }
 
+    @Test
+    public void testComplexGuard() {
+        CallTarget root = createCallTarget(GuardComplexTestFactory.getInstance());
+        assertEquals("do1", root.call(1));
+        assertEquals("do1", root.call(2));
+        assertEquals("do2", root.call(3));
+        assertEquals("do1", root.call(0));
+    }
+
+    @NodeChild
+    static class GuardComplexTest extends ValueNode {
+
+        int field1 = 1;
+        static int field2 = 2;
+
+        @Specialization(guards = {"method2(method1(field1 == 1), value <= 2)", "field2 == 2"})
+        static String do1(int value) {
+            return "do1";
+        }
+
+        @Specialization
+        static String do2(int value) {
+            return "do2";
+        }
+
+        static boolean method1(boolean value) {
+            return value;
+        }
+
+        boolean method2(boolean value1, boolean value2) {
+            return value1 && value2;
+        }
+    }
+
+    @NodeChild
+    static class ErrorGuardNotTest extends ValueNode {
+        @ExpectError("Error parsing expression '!value == 1': The operator ! is undefined for the argument type int.")
+        @Specialization(guards = "!value == 1")
+        static String do1(int value) {
+            return "do1";
+        }
+    }
+
+    @NodeChild
+    static class ErrorIncompatibleReturnTypeTest extends ValueNode {
+
+        @ExpectError("Incompatible return type int. Guards must return boolean.")
+        @Specialization(guards = "1")
+        static String do1(int value) {
+            return "do1";
+        }
+
+    }
+
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -69,7 +69,7 @@
             return true;
         }
 
-        @Specialization(guards = "guard ()")
+        @Specialization(guards = "guard()")
         int do1() {
             return 42;
         }
@@ -214,7 +214,7 @@
             return true;
         }
 
-        @ExpectError("No compatible guard with method name 'guard(' found.%")
+        @ExpectError("Error parsing expression 'guard(': -- line 1 col 7: \")\" expected%")
         @Specialization(guards = "guard(")
         int do1() {
             return 42;
@@ -227,7 +227,7 @@
             return true;
         }
 
-        @ExpectError("No compatible guard with method name 'guard)' found.%")
+        @ExpectError("Error parsing expression 'guard)': -- line 1 col 6: EOF expected%")
         @Specialization(guards = "guard)")
         int do1() {
             return 42;
@@ -241,7 +241,7 @@
             return true;
         }
 
-        @ExpectError("Guard parameter 'a' for guard 'guard' could not be mapped to a declared child node.")
+        @ExpectError("Error parsing expression 'guard(a)': a cannot be resolved.")
         @Specialization(guards = "guard(a)")
         int do1() {
             return 42;
@@ -255,7 +255,7 @@
             return true;
         }
 
-        @ExpectError("Guard parameter 'a' for guard 'guard' could not be mapped to a declared child node.")
+        @ExpectError("Error parsing expression 'guard(a)': a cannot be resolved.")
         @Specialization(guards = "guard(a)")
         int do1(int b) {
             return b;
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -45,7 +45,7 @@
             return true;
         }
 
-        @Specialization(guards = "!guard")
+        @Specialization(guards = "!guard()")
         int do1() {
             throw new AssertionError();
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -182,7 +182,7 @@
             return false;
         }
 
-        @Specialization(guards = "foo")
+        @Specialization(guards = "foo()")
         int do2() {
             return 1;
         }
@@ -206,7 +206,7 @@
         }
 
         @ExpectError("Specialization is not reachable. It is shadowed by do2().")
-        @Specialization(guards = "foo")
+        @Specialization(guards = "foo()")
         int do1() {
             return 1;
         }
@@ -219,7 +219,7 @@
             return false;
         }
 
-        @Specialization(guards = "foo")
+        @Specialization(guards = "foo()")
         int do2() {
             return 1;
         }
@@ -237,106 +237,13 @@
             return false;
         }
 
-        @Specialization(guards = "foo")
-        int do2() {
-            return 1;
-        }
-
-        @ExpectError("Specialization is not reachable. It is shadowed by do2().")
-        @Specialization(guards = "foo")
-        int do1() {
-            return 2;
-        }
-
-    }
-
-    @NodeAssumptions({"a1"})
-    static class ReachabilityAssumption1 extends ValueNode {
-
-        @Specialization(assumptions = "a1")
-        int do2() {
-            return 1;
-        }
-
-        @Specialization
-        int do1() {
-            return 2;
-        }
-
-    }
-
-    @NodeAssumptions({"a1"})
-    static class ReachabilityAssumption2 extends ValueNode {
-
-        @Specialization(assumptions = "a1")
+        @Specialization(guards = "foo()")
         int do2() {
             return 1;
         }
 
         @ExpectError("Specialization is not reachable. It is shadowed by do2().")
-        @Specialization(assumptions = "a1")
-        int do1() {
-            return 2;
-        }
-
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    static class ReachabilityAssumption3 extends ValueNode {
-
-        @Specialization(assumptions = {"a1", "a2"})
-        int do2() {
-            return 1;
-        }
-
-        @Specialization(assumptions = "a1")
-        int do1() {
-            return 2;
-        }
-
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    static class ReachabilityAssumption4 extends ValueNode {
-
-        @Specialization(assumptions = "a1")
-        int do2() {
-            return 1;
-        }
-
-        @Specialization(assumptions = "a2")
-        int do1() {
-            return 2;
-        }
-
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    static class ReachabilityAssumption5 extends ValueNode {
-
-        @Specialization
-        int do2() {
-            return 1;
-        }
-
-        @ExpectError("Specialization is not reachable. It is shadowed by do2().")
-        @Specialization(assumptions = "a2")
-        int do1() {
-            return 2;
-        }
-
-    }
-
-    @NodeAssumptions({"a1", "a2"})
-    static class ReachabilityAssumption6 extends ValueNode {
-
-        @Specialization(assumptions = {"a1"})
-        int do2() {
-            return 1;
-        }
-
-        @ExpectError("Specialization is not reachable. It is shadowed by do2().")
-        @Specialization(assumptions = {"a1", "a2"})
+        @Specialization(guards = "foo()")
         int do1() {
             return 2;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ShortCircuitTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ShortCircuitTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -119,7 +119,7 @@
             return false;
         }
 
-        @Specialization(guards = "guard")
+        @Specialization(guards = "guard(a, hasB, b)")
         int doIt(int a, boolean hasB, int b) {
             return a + b;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -74,29 +74,17 @@
     @NodeChild("a")
     static class SourceSection0 extends ValueNode {
 
-        boolean isOne(int a) {
-            return a == 1;
-        }
-
-        boolean isTwo(int a) {
-            return a == 2;
-        }
-
-        boolean isThree(int a) {
-            return a == 3;
-        }
-
-        @Specialization(guards = "isOne")
+        @Specialization(guards = "a == 1")
         int do1(int a) {
             return a;
         }
 
-        @Specialization(guards = "isTwo")
+        @Specialization(guards = "a == 2")
         int do2(int a) {
             return a;
         }
 
-        @Specialization(guards = "isThree")
+        @Specialization(guards = "a == 3")
         int do3(int a) {
             return a;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -212,7 +212,7 @@
             return a == 1;
         }
 
-        @Specialization(guards = "guard0")
+        @Specialization(guards = "guard0(a)")
         int do2(int a) {
             return a;
         }
@@ -309,7 +309,7 @@
 
         static int fallthrough1;
 
-        @Specialization(guards = "isDo1", rewriteOn = ArithmeticException.class)
+        @Specialization(guards = "isDo1(a)", rewriteOn = ArithmeticException.class)
         int do1(int a) throws ArithmeticException {
             if (a == 0) {
                 fallthrough1++;
@@ -322,7 +322,7 @@
             return a == 0 || a == 1;
         }
 
-        @Specialization(guards = "isDo1")
+        @Specialization(guards = "isDo1(a)")
         int do2(int a) {
             return a;
         }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java	Thu Feb 12 04:01:46 2015 +0100
@@ -28,9 +28,6 @@
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestElseConnectionBug1Factory;
 import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestElseConnectionBug2Factory;
-import com.oracle.truffle.api.dsl.test.SpecializationGroupingTestFactory.TestGroupingFactory;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.SimpleTypes;
-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.*;
@@ -43,119 +40,6 @@
 public class SpecializationGroupingTest {
 
     @Test
-    public void testGrouping() {
-        MockAssumption a1 = new MockAssumption(true);
-        MockAssumption a3 = new MockAssumption(true);
-
-        TestRootNode<TestGrouping> root = TestHelper.createRoot(TestGroupingFactory.getInstance(), a1, a3);
-
-        SimpleTypes.intCast = 0;
-        SimpleTypes.intCheck = 0;
-        TestGrouping.true1 = 0;
-        TestGrouping.false1 = 0;
-        TestGrouping.true2 = 0;
-        TestGrouping.false2 = 0;
-        TestGrouping.true3 = 0;
-
-        Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21));
-        Assert.assertEquals(4, TestGrouping.true1);
-        Assert.assertEquals(0, TestGrouping.false1);
-        Assert.assertEquals(4, TestGrouping.true2);
-        Assert.assertEquals(5, TestGrouping.false2);
-        Assert.assertEquals(5, TestGrouping.true3);
-        Assert.assertEquals(10, SimpleTypes.intCheck);
-        Assert.assertEquals(8, SimpleTypes.intCast);
-        Assert.assertEquals(4, a1.checked);
-        Assert.assertEquals(4, a3.checked);
-
-        Assert.assertEquals(42, TestHelper.executeWith(root, 21, 21));
-        Assert.assertEquals(5, TestGrouping.true1);
-        Assert.assertEquals(0, TestGrouping.false1);
-        Assert.assertEquals(5, TestGrouping.true2);
-        Assert.assertEquals(6, TestGrouping.false2);
-        Assert.assertEquals(6, TestGrouping.true3);
-
-        Assert.assertEquals(5, a1.checked);
-        Assert.assertEquals(5, a3.checked);
-        Assert.assertEquals(10, SimpleTypes.intCheck);
-        Assert.assertEquals(8, SimpleTypes.intCast);
-
-    }
-
-    @SuppressWarnings("unused")
-    @NodeChildren({@NodeChild, @NodeChild})
-    @NodeAssumptions({"a1", "a3"})
-    public abstract static class TestGrouping extends ValueNode {
-
-        private static int true1;
-        private static int false1;
-        private static int true2;
-        private static int false2;
-        private static int true3;
-
-        protected boolean true1(int value) {
-            true1++;
-            return true;
-        }
-
-        protected boolean false1(int value, int value2) {
-            false1++;
-            return false;
-        }
-
-        protected boolean true2(int value) {
-            true2++;
-            return true;
-        }
-
-        protected boolean false2(int value) {
-            false2++;
-            return false;
-        }
-
-        protected boolean true3(int value) {
-            true3++;
-            return true;
-        }
-
-        @Specialization
-        public int fail(int value1, String value2) {
-            throw new AssertionError();
-        }
-
-        @Specialization(guards = {"true1", "true2", "!false2", "true3"}, assumptions = {"a1", "a3"}, rewriteOn = RuntimeException.class)
-        public int throwRewrite(int value1, int value2) {
-            throw new RuntimeException();
-        }
-
-        @Specialization(guards = {"true1", "true2", "!false2", "true3"}, contains = "throwRewrite", assumptions = {"a1", "a3"})
-        public int success(int value1, int value2) {
-            return value1 + value2;
-        }
-
-        @Specialization(guards = {"true1", "true2", "!false2", "!true3"}, assumptions = {"a1", "a3"})
-        public int fail5(int value1, int value2) {
-            throw new AssertionError();
-        }
-
-        @Specialization(guards = {"true1", "true2", "false2"}, assumptions = {"a1", "a3"})
-        public int fail4(int value1, int value2) {
-            throw new AssertionError();
-        }
-
-        @Specialization(guards = {"true1", "true2"}, assumptions = {"a1", "a3"})
-        public int fail2break(int value1, int value2) {
-            throw new AssertionError();
-        }
-
-        @Specialization(guards = {"true1", "false1"})
-        public int fail1(int value1, int value2) {
-            throw new AssertionError();
-        }
-
-    }
-
-    @Test
     public void testElseConnectionBug1() {
         CallTarget target = TestHelper.createCallTarget(TestElseConnectionBug1Factory.create(new GenericInt()));
         Assert.assertEquals(42, target.call());
@@ -165,17 +49,17 @@
     @NodeChild(value = "genericChild", type = GenericInt.class)
     public abstract static class TestElseConnectionBug1 extends ValueNode {
 
-        @Specialization(rewriteOn = {SlowPathException.class}, guards = "isInitialized")
+        @Specialization(rewriteOn = {SlowPathException.class}, guards = "isInitialized(value)")
         public int do1(int value) throws SlowPathException {
             throw new SlowPathException();
         }
 
-        @Specialization(contains = "do1", guards = "isInitialized")
+        @Specialization(contains = "do1", guards = "isInitialized(value)")
         public int do2(int value) {
             return value == 42 ? value : 0;
         }
 
-        @Specialization(guards = "!isInitialized")
+        @Specialization(guards = "!isInitialized(value)")
         public Object do3(int value) {
             throw new AssertionError();
         }
@@ -208,17 +92,17 @@
     @NodeChild
     public abstract static class TestElseConnectionBug2 extends ValueNode {
 
-        @Specialization(guards = "guard0")
+        @Specialization(guards = "guard0(value)")
         public int do1(int value) {
             throw new AssertionError();
         }
 
-        @Specialization(guards = "guard1")
+        @Specialization(guards = "guard1(value)")
         public int do2(int value) {
             throw new AssertionError();
         }
 
-        @Specialization(guards = "!guard0")
+        @Specialization(guards = "!guard0(value)")
         public int do3(int value) {
             return value;
         }
@@ -232,36 +116,4 @@
         }
     }
 
-    private static class MockAssumption implements Assumption {
-
-        int checked;
-
-        private final boolean valid;
-
-        public MockAssumption(boolean valid) {
-            this.valid = valid;
-        }
-
-        public void check() throws InvalidAssumptionException {
-            checked++;
-            if (!valid) {
-                throw new InvalidAssumptionException();
-            }
-        }
-
-        public boolean isValid() {
-            checked++;
-            return valid;
-        }
-
-        public void invalidate() {
-            throw new UnsupportedOperationException();
-        }
-
-        public String getName() {
-            throw new UnsupportedOperationException();
-        }
-
-    }
-
 }
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Thu Feb 12 04:01:46 2015 +0100
@@ -84,6 +84,22 @@
         return Truffle.getRuntime().createCallTarget(node);
     }
 
+    static RootCallTarget createCallTarget(NodeFactory<? extends ValueNode> factory, Object... constants) {
+        return Truffle.getRuntime().createCallTarget(createRoot(factory, constants));
+    }
+
+    static boolean assertionsEnabled() {
+        boolean assertOn = false;
+        // *assigns* true if assertions are on.
+        assert (assertOn = true) == true;
+        return assertOn;
+    }
+
+    @SuppressWarnings("unchecked")
+    static <T extends ValueNode> T getNode(CallTarget target) {
+        return ((TestRootNode<T>) ((RootCallTarget) target).getRootNode()).getNode();
+    }
+
     static <E> Object executeWith(TestRootNode<? extends ValueNode> node, Object... values) {
         return createCallTarget(node).call(values);
     }
--- /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/examples/ExampleNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,123 @@
+/*
+ * 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.examples;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.internal.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+@TypeSystemReference(ExampleTypes.class)
+@NodeChild(value = "args", type = ExampleNode[].class)
+public abstract class ExampleNode extends Node {
+
+    public Object execute(@SuppressWarnings("unused") VirtualFrame frame) {
+        // will get implemented by the DSL.
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String toString() {
+        if (this instanceof SpecializedNode) {
+            return ((SpecializedNode) this).getSpecializationNode().toString();
+        } else {
+            return super.toString();
+        }
+    }
+
+    public static CallTarget createTarget(ExampleNode node) {
+        return Truffle.getRuntime().createCallTarget(new ExampleRootNode(node));
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T getNode(CallTarget target) {
+        return (T) ((ExampleRootNode) ((RootCallTarget) target).getRootNode()).child;
+    }
+
+    public static ExampleNode[] createArguments(int count) {
+        ExampleNode[] nodes = new ExampleNode[count];
+        for (int i = 0; i < count; i++) {
+            nodes[i] = new ExampleArgumentNode(i);
+        }
+        return nodes;
+    }
+
+    private static class ExampleRootNode extends RootNode {
+
+        @Child ExampleNode child;
+
+        public ExampleRootNode(ExampleNode child) {
+            this.child = child;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return child.execute(frame);
+        }
+
+    }
+
+    private static class ExampleArgumentNode extends ExampleNode {
+
+        private final int index;
+
+        public ExampleArgumentNode(int index) {
+            this.index = index;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            Object[] arguments = frame.getArguments();
+            if (index < arguments.length) {
+                return arguments[index];
+            }
+            return null;
+        }
+    }
+
+    public static CallTarget createDummyTarget(int argumentIndex) {
+        return Truffle.getRuntime().createCallTarget(new DummyCallRootNode(argumentIndex));
+    }
+
+    private static class DummyCallRootNode extends RootNode {
+
+        private final int argumentIndex;
+
+        public DummyCallRootNode(int argumentIndex) {
+            this.argumentIndex = argumentIndex;
+        }
+
+        @Override
+        public Object execute(VirtualFrame frame) {
+            return frame.getArguments()[argumentIndex];
+        }
+
+        @Override
+        public String toString() {
+            return "DummyRootNode[arg = " + argumentIndex + "]";
+        }
+
+    }
+
+}
--- /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/examples/ExampleTypes.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,40 @@
+/*
+ * 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.examples;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.examples.FunctionCall.Function;
+import com.oracle.truffle.api.dsl.test.examples.Interop.TruffleObject;
+import com.oracle.truffle.api.dsl.test.examples.RubyCall.InternalMethod;
+import com.oracle.truffle.api.dsl.test.examples.RubyCall.RubyObject;
+import com.oracle.truffle.api.dsl.test.examples.StableDispatch.SLFunction;
+
+@TypeSystem({int.class, double.class, boolean.class, TruffleObject.class, SLFunction.class, RubyObject.class, Function.class, InternalMethod.class, int[].class, double[].class, Object[].class})
+public class ExampleTypes {
+
+    @ImplicitCast
+    public static double castInt(int intValue) {
+        return intValue;
+    }
+
+}
--- /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/examples/FunctionCall.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,151 @@
+/*
+ * 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.examples;
+
+import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*;
+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.examples.FunctionCallFactory.FunctionCallNodeGen;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * This example illustrates how {@link Cached} can be used to implement function calls that use
+ * local state for its guards. If there are always distinct Function objects with distinct
+ * CallTargets then we can use the directCallFunctionGuard specialization. If there are two Function
+ * instances cached with the same CallTarget then we use the directCall cache. We do this because
+ * the directCallFunctionGuard specialization can use a faster guard.
+ */
+@SuppressWarnings("unused")
+public class FunctionCall {
+
+    @Test
+    public void testFunctionCall() {
+        assertEquals(2, FunctionCallNode.CACHE_SIZE);
+
+        CallTarget dummyTarget1 = createDummyTarget(0);
+        CallTarget dummyTarget2 = createDummyTarget(0);
+        CallTarget dummyTarget3 = createDummyTarget(0);
+
+        Function dummyFunction1 = new Function(dummyTarget1);
+        Function dummyFunction2 = new Function(dummyTarget2);
+        Function dummyFunction3 = new Function(dummyTarget2); // same target as dummyFunction2
+        Function dummyFunction4 = new Function(dummyTarget3);
+
+        FunctionCallNode node = FunctionCallNodeGen.create(createArguments(2));
+        CallTarget target = createTarget(node);
+        assertEquals(42, target.call(dummyFunction1, 42));
+        assertEquals(43, target.call(dummyFunction2, 43));
+        assertEquals(44, target.call(dummyFunction3, 44)); // transition to directCall
+        assertEquals(2, node.directCallFunctionGuard);
+        assertEquals(1, node.directCall);
+
+        assertEquals(42, target.call(dummyFunction1, 42));
+        assertEquals(43, target.call(dummyFunction2, 43));
+        assertEquals(2, node.directCallFunctionGuard);
+        assertEquals(3, node.directCall);
+
+        assertEquals(44, target.call(dummyFunction4, 44)); // transition to indirectCall
+        assertEquals(2, node.directCallFunctionGuard);
+        assertEquals(3, node.directCall);
+        assertEquals(1, node.indirectCall);
+
+        assertEquals(42, target.call(dummyFunction1, 42));
+        assertEquals(43, target.call(dummyFunction2, 43));
+        assertEquals(44, target.call(dummyFunction3, 44));
+        assertEquals(2, node.directCallFunctionGuard);
+        assertEquals(3, node.directCall);
+        assertEquals(4, node.indirectCall);
+    }
+
+    public static class FunctionCallNode extends ExampleNode {
+
+        public static final int CACHE_SIZE = 2;
+
+        private Function[] cachedFunctions = new Function[CACHE_SIZE];
+
+        private int directCallFunctionGuard;
+        private int directCall;
+        private int indirectCall;
+
+        @Specialization(limit = "CACHE_SIZE", guards = {"function == cachedFunction", "cacheFunctionTarget(cachedFunction)"})
+        public Object directCallFunctionGuard(VirtualFrame frame, Function function, Object argument,  //
+                        @Cached("function") Function cachedFunction, //
+                        @Cached("create(cachedFunction.getTarget())") DirectCallNode callNode) {
+            directCallFunctionGuard++;
+            return callNode.call(frame, new Object[]{argument});
+        }
+
+        protected final boolean cacheFunctionTarget(Function function) {
+            CompilerAsserts.neverPartOfCompilation();
+            if (cachedFunctions != null) {
+                for (int i = 0; i < cachedFunctions.length; i++) {
+                    Function cachedFunction = cachedFunctions[i];
+                    if (cachedFunction == null) {
+                        cachedFunctions[i] = function;
+                        return true;
+                    } else if (cachedFunction == function) {
+                        return true;
+                    } else if (cachedFunction.getTarget() == function.getTarget()) {
+                        cachedFunctions = null;
+                        return false;
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Specialization(limit = "CACHE_SIZE", contains = "directCallFunctionGuard", guards = {"function.getTarget() == cachedTarget"})
+        protected Object directCall(VirtualFrame frame, Function function, Object argument,  //
+                        @Cached("function.getTarget()") CallTarget cachedTarget, //
+                        @Cached("create(cachedTarget)") DirectCallNode callNode) {
+            directCall++;
+            return callNode.call(frame, new Object[]{argument});
+        }
+
+        @Specialization(contains = "directCall")
+        protected Object indirectCall(VirtualFrame frame, Function function, Object argument, //
+                        @Cached("create()") IndirectCallNode callNode) {
+            indirectCall++;
+            return callNode.call(frame, function.getTarget(), new Object[]{argument});
+        }
+    }
+
+    public static class Function {
+
+        private final CallTarget target;
+
+        public Function(CallTarget target) {
+            this.target = target;
+        }
+
+        public CallTarget getTarget() {
+            return target;
+        }
+    }
+
+}
--- /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/examples/Interop.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,109 @@
+/*
+ * 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.examples;
+
+import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*;
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.examples.InteropFactory.UseInteropNodeGen;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * This example aims to illustrate how the {@link Cached} annotation can be used to implement a
+ * cache for a simplified language interoperability pattern.
+ */
+public class Interop {
+
+    @Test
+    public void testInterop() {
+        UseInterop node = UseInteropNodeGen.create(createArguments(2));
+        CallTarget target = createTarget(node);
+        TruffleObject o1 = new TruffleObject();
+        TruffleObject o2 = new TruffleObject();
+        TruffleObject o3 = new TruffleObject();
+        TruffleObject o4 = new TruffleObject();
+        assertEquals(42, target.call(o1, 42));
+        assertEquals(43, target.call(o2, 43));
+        assertEquals(44, target.call(o3, 44));
+        assertEquals(3, node.cached);
+        assertEquals(0, node.generic);
+        assertEquals(45, target.call(o4, 45)); // operation gets generic
+        assertEquals(42, target.call(o1, 42));
+        assertEquals(43, target.call(o2, 43));
+        assertEquals(44, target.call(o3, 44));
+        assertEquals(3, node.cached);
+        assertEquals(4, node.generic);
+    }
+
+    public static class UseInterop extends ExampleNode {
+
+        int cached = 0;
+        int generic = 0;
+
+        @Specialization(guards = "operation.accept(target)")
+        protected Object interopCached(VirtualFrame frame, TruffleObject target, Object value, //
+                        @Cached("target.createOperation()") TruffleObjectOperation operation) {
+            cached++;
+            return operation.execute(frame, target, value);
+        }
+
+        @Specialization(contains = "interopCached")
+        protected Object interopGeneric(VirtualFrame frame, TruffleObject target, Object value) {
+            generic++;
+            return target.createOperation().execute(frame, target, value);
+        }
+    }
+
+    public abstract static class TruffleObjectOperation extends Node {
+
+        public abstract boolean accept(TruffleObject object);
+
+        public abstract Object execute(VirtualFrame frame, Object target, Object value);
+
+    }
+
+    public static class TruffleObject {
+
+        @TruffleBoundary
+        public TruffleObjectOperation createOperation() {
+            return new TruffleObjectOperation() {
+                @Override
+                public Object execute(VirtualFrame frame, Object target, Object value) {
+                    return value;
+                }
+
+                @Override
+                public boolean accept(TruffleObject object) {
+                    return TruffleObject.this == object;
+                }
+            };
+        }
+    }
+
+}
--- /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/examples/MathPow.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,144 @@
+/*
+ * 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.examples;
+
+import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*;
+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.examples.MathPowFactory.MathPowNodeGen;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * This example shows possible specializations for a simplified math pow node. It demonstrates how
+ * multiple caches can coexist within in the same node. This example does not show the best possible
+ * specializations for math.pow.
+ *
+ * Note: int values are implicitly casted to double values.
+ */
+@SuppressWarnings("unused")
+public class MathPow extends Node {
+
+    @Test
+    public void testPow() {
+        MathPowNode node = MathPowNodeGen.create(createArguments(2));
+        CallTarget target = createTarget(node);
+
+        // start with doPowCached
+        assertEquals(1D, target.call(1D, 1));
+        assertEquals(2D, target.call(2D, 1));
+        assertEquals(3D, target.call(3D, 1));
+        assertEquals(3, node.doPowCached);
+        assertEquals(0, node.doPowCachedExponent);
+
+        // transition to doPowCachedExponent
+        assertEquals(4D, target.call(4D, 1));
+        assertEquals(5D, target.call(5D, 1));
+        assertEquals(6D, target.call(6D, 1));
+        assertEquals(16D, target.call(4D, 2));
+        assertEquals(125D, target.call(5D, 3));
+        assertEquals(5, node.doPowCachedExponent);
+        assertEquals(0, node.doPowDoubleInt);
+
+        // transition to doPowDoubleInt
+        assertEquals(4D * 4D * 4D * 4D, target.call(4D, 4));
+        assertEquals(5D * 5D * 5D * 5D * 5D, target.call(5D, 5));
+        assertEquals(5, node.doPowCachedExponent);
+        assertEquals(2, node.doPowDoubleInt);
+
+        // transition to doPow
+        assertEquals(5D, target.call(5D, 1D));
+        assertEquals(2D, target.call(2D, 1D));
+
+        assertEquals(3, node.doPowCached);
+        assertEquals(5, node.doPowCachedExponent);
+        assertEquals(2, node.doPowDoubleInt);
+        assertEquals(2, node.doPow);
+    }
+
+    public static class MathPowNode extends ExampleNode {
+
+        // test flags
+        int doPowCached;
+        int doPowCachedExponent;
+        int doPowDoubleInt;
+        int doPow;
+
+        @Specialization(guards = {"base == cachedBase", "exponent == cachedExponent"})
+        double doPowCached(double base, int exponent, //
+                        @Cached("base") double cachedBase, //
+                        @Cached("exponent") int cachedExponent, //
+                        @Cached("cachePow(cachedBase, cachedExponent)") double cachedResult) {
+            doPowCached++;
+            return cachedResult;
+        }
+
+        /*
+         * We could just use the doPow specialization instead. But this makes the number of doPow
+         * calls more difficult to assert.
+         */
+        protected static double cachePow(double base, int exponent) {
+            return Math.pow(base, exponent);
+        }
+
+        @Specialization(contains = "doPowCached", guards = {"exponent == cachedExponent", "cachedExponent <= 10"})
+        @ExplodeLoop
+        double doPowCachedExponent(double base, int exponent, @Cached("exponent") int cachedExponent) {
+            doPowCachedExponent++;
+            double result = 1.0;
+            for (int i = 0; i < cachedExponent; i++) {
+                result *= base;
+            }
+            return result;
+        }
+
+        @Specialization(contains = "doPowCachedExponent", guards = "exponent >= 0")
+        double doPowDoubleInt(double base, int exponent) {
+            doPowDoubleInt++;
+            // Uses binary decomposition to limit the number of
+            // multiplications; see the discussion in "Hacker's Delight" by Henry
+            // S. Warren, Jr., figure 11-6, page 213.
+            double b = base;
+            int e = exponent;
+            double result = 1;
+            while (e > 0) {
+                if ((e & 1) == 1) {
+                    result *= b;
+                }
+                e >>= 1;
+                b *= b;
+            }
+            return result;
+        }
+
+        @Specialization(contains = {"doPowCached", "doPowDoubleInt"})
+        double doPow(double base, double exponent) {
+            doPow++;
+            return Math.pow(base, exponent);
+        }
+    }
+
+}
--- /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/examples/RubyCall.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,302 @@
+/*
+ * 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.examples;
+
+import static com.oracle.truffle.api.dsl.test.examples.ExampleNode.*;
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.internal.*;
+import com.oracle.truffle.api.dsl.test.examples.RubyCallFactory.RubyDispatchNodeGen;
+import com.oracle.truffle.api.dsl.test.examples.RubyCallFactory.RubyHeadNodeGen;
+import com.oracle.truffle.api.dsl.test.examples.RubyCallFactory.RubyLookupNodeGen;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+
+/**
+ * This example illustrates a simplified version of a Ruby function call semantics (RubyHeadNode).
+ * The example usage shows how methods can be redefined in this implementation.
+ */
+@SuppressWarnings("unused")
+public class RubyCall {
+
+    @Test
+    public void testCall() {
+        RubyHeadNode node = RubyHeadNodeGen.create(createArguments(4));
+        CallTarget nodeTarget = createTarget(node);
+        final Object firstArgument = "someArgument";
+
+        // dummyMethod is just going to return the some argument of the function
+        final Object testMethodName = "getSomeArgument";
+        // implementation returns first argument
+        InternalMethod aClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(3));
+        // implementation returns second argument
+        InternalMethod bClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(4));
+        // implementation returns third argument
+        InternalMethod cClassTestMethod = new InternalMethod(ExampleNode.createDummyTarget(5));
+
+        // defines hierarchy C extends B extends A
+        RubyClass aClass = new RubyClass("A", null);
+        RubyClass bClass = new RubyClass("B", aClass);
+        RubyClass cClass = new RubyClass("C", bClass);
+
+        RubyObject aInstance = new RubyObject(aClass);
+        RubyObject bInstance = new RubyObject(bClass);
+        RubyObject cInstance = new RubyObject(cClass);
+
+        // undefined method call
+        assertEquals(RubyObject.NIL, nodeTarget.call(cInstance, testMethodName, null, new Object[]{firstArgument}));
+
+        // method defined in a
+        aClass.addMethod(testMethodName, aClassTestMethod);
+        assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument}));
+        assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{firstArgument}));
+        assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{firstArgument}));
+
+        // method redefined in b
+        bClass.addMethod(testMethodName, bClassTestMethod);
+        assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument}));
+        assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{null, firstArgument}));
+        assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{null, firstArgument}));
+
+        // method redefined in c
+        cClass.addMethod(testMethodName, cClassTestMethod);
+        assertEquals(firstArgument, nodeTarget.call(aInstance, testMethodName, null, new Object[]{firstArgument}));
+        assertEquals(firstArgument, nodeTarget.call(bInstance, testMethodName, null, new Object[]{null, firstArgument}));
+        assertEquals(firstArgument, nodeTarget.call(cInstance, testMethodName, null, new Object[]{null, null, firstArgument}));
+
+    }
+
+    public static class RubyHeadNode extends ExampleNode {
+
+        @Child private RubyLookupNode lookup = RubyLookupNodeGen.create(null);
+        @Child private RubyDispatchNode dispatch = RubyDispatchNodeGen.create(null);
+
+        @Specialization
+        public Object doCall(VirtualFrame frame, Object receiverObject, Object methodName, Object blockObject, Object... argumentsObjects) {
+            InternalMethod method = lookup.executeLookup(frame, receiverObject, methodName);
+
+            Object[] packedArguments = new Object[argumentsObjects.length + 3];
+            packedArguments[0] = method;
+            packedArguments[1] = receiverObject;
+            packedArguments[2] = blockObject;
+            System.arraycopy(argumentsObjects, 0, packedArguments, 3, argumentsObjects.length);
+
+            return dispatch.executeDispatch(frame, method, packedArguments);
+        }
+    }
+
+    public abstract static class RubyLookupNode extends ExampleNode {
+
+        public abstract InternalMethod executeLookup(VirtualFrame frame, Object receiverObject, Object methodName);
+
+        @Specialization(guards = "receiver.getRubyClass() == cachedClass", assumptions = "cachedClass.getDependentAssumptions()")
+        protected static InternalMethod cachedLookup(RubyObject receiver, Object name, //
+                        @Cached("receiver.getRubyClass()") RubyClass cachedClass, //
+                        @Cached("genericLookup(receiver, name)") InternalMethod cachedLookup) {
+            return cachedLookup;
+        }
+
+        @Specialization(contains = "cachedLookup")
+        protected static InternalMethod genericLookup(RubyObject receiver, Object name) {
+            return receiver.getRubyClass().lookup(name);
+        }
+
+    }
+
+    @ImportStatic(InternalMethod.class)
+    public abstract static class RubyDispatchNode extends ExampleNode {
+
+        public abstract Object executeDispatch(VirtualFrame frame, InternalMethod function, Object[] packedArguments);
+
+        /*
+         * Please note that cachedMethod != METHOD_MISSING is invoked once at specialization
+         * instantiation. It is never executed on the fast path.
+         */
+        @Specialization(guards = {"method == cachedMethod", "cachedMethod != METHOD_MISSING"})
+        protected static Object directCall(VirtualFrame frame, InternalMethod method, Object[] arguments, //
+                        @Cached("method") InternalMethod cachedMethod, //
+                        @Cached("create(cachedMethod.getTarget())") DirectCallNode callNode) {
+            return callNode.call(frame, arguments);
+        }
+
+        /*
+         * The method == METHOD_MISSING can fold if the RubyLookup results just in a single entry
+         * returning the constant METHOD_MISSING.
+         */
+        @Specialization(guards = "method == METHOD_MISSING")
+        protected static Object methodMissing(VirtualFrame frame, InternalMethod method, Object[] arguments) {
+            // a real implementation would do a call to a method named method_missing here
+            return RubyObject.NIL;
+        }
+
+        @Specialization(contains = "directCall", guards = "method != METHOD_MISSING")
+        protected static Object indirectCall(VirtualFrame frame, InternalMethod method, Object[] arguments, //
+                        @Cached("create()") IndirectCallNode callNode) {
+            return callNode.call(frame, method.getTarget(), arguments);
+        }
+
+        @Override
+        public String toString() {
+            return ((SpecializedNode) this).getSpecializationNode().toString();
+        }
+    }
+
+    public static final class RubyObject {
+
+        public static final RubyObject NIL = new RubyObject(null);
+
+        private final RubyClass rubyClass;
+
+        public RubyObject(RubyClass rubyClass) {
+            this.rubyClass = rubyClass;
+        }
+
+        public RubyClass getRubyClass() {
+            return rubyClass;
+        }
+
+        @Override
+        public String toString() {
+            return "RubyObject[class=" + rubyClass + "]";
+        }
+
+    }
+
+    public static final class RubyClass /* this would extend RubyModule */{
+
+        private final String name;
+        private final RubyClass parent; // this would be a RubyModule
+        private final CyclicAssumption unmodified;
+        private final Map<Object, InternalMethod> methods = new HashMap<>();
+        private Assumption[] cachedDependentAssumptions;
+        private final int depth;
+
+        public RubyClass(String name, RubyClass parent) {
+            this.name = name;
+            this.parent = parent;
+            this.unmodified = new CyclicAssumption("unmodified class " + name);
+
+            // lookup depth for array allocation
+            RubyClass clazz = parent;
+            int currentDepth = 1;
+            while (clazz != null) {
+                currentDepth++;
+                clazz = clazz.parent;
+            }
+            this.depth = currentDepth;
+        }
+
+        @TruffleBoundary
+        public InternalMethod lookup(Object methodName) {
+            InternalMethod method = methods.get(methodName);
+            if (method == null) {
+                if (parent != null) {
+                    return parent.lookup(methodName);
+                } else {
+                    return InternalMethod.METHOD_MISSING;
+                }
+            } else {
+                return method;
+            }
+        }
+
+        @TruffleBoundary
+        public void addMethod(Object methodName, InternalMethod method) {
+            // check for existing method omitted for simplicity
+            this.methods.put(methodName, method);
+            this.unmodified.invalidate();
+        }
+
+        /*
+         * Method collects all unmodified assumptions in the class hierarchy. The result is cached
+         * per class to void recreation per call site.
+         */
+        @TruffleBoundary
+        public Assumption[] getDependentAssumptions() {
+            Assumption[] dependentAssumptions = cachedDependentAssumptions;
+            if (dependentAssumptions != null) {
+                // we can use the cached dependent assumptions only if they are still valid
+                for (Assumption assumption : cachedDependentAssumptions) {
+                    if (!assumption.isValid()) {
+                        dependentAssumptions = null;
+                        break;
+                    }
+                }
+            }
+            if (dependentAssumptions == null) {
+                cachedDependentAssumptions = dependentAssumptions = createDependentAssumptions();
+            }
+            return dependentAssumptions;
+        }
+
+        @Override
+        public String toString() {
+            return "RubyClass[name=" + name + "]";
+        }
+
+        private Assumption[] createDependentAssumptions() {
+            Assumption[] dependentAssumptions;
+            RubyClass clazz = this;
+            dependentAssumptions = new Assumption[depth];
+
+            // populate array
+            int index = 0;
+            do {
+                dependentAssumptions[index] = clazz.unmodified.getAssumption();
+                index++;
+                clazz = clazz.parent;
+            } while (clazz != null);
+            return dependentAssumptions;
+        }
+    }
+
+    public static final class InternalMethod {
+
+        public static final InternalMethod METHOD_MISSING = new InternalMethod(null);
+
+        private final CallTarget target;
+
+        public InternalMethod(CallTarget target) {
+            this.target = target;
+        }
+
+        public CallTarget getTarget() {
+            return target;
+        }
+
+        @Override
+        public String toString() {
+            return "InternalMethod[target=" + getTarget() + "]";
+        }
+
+    }
+
+}
--- /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/examples/StableDispatch.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,80 @@
+/*
+ * 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.examples;
+
+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.api.utilities.*;
+
+/**
+ * This example is based on the SLDispatchNode of SimpleLanguage. It shows how to implement a simple
+ * inline cache with an assumption that needs to be checked.
+ *
+ * Note that if an assumption is invalidated the specialization instantiation is removed.
+ */
+@SuppressWarnings("unused")
+@NodeChildren({@NodeChild("function"), @NodeChild("arguments")})
+public class StableDispatch {
+
+    public static class StableDispatchNode extends ExampleNode {
+
+        @Specialization(guards = "function == cachedFunction", assumptions = "cachedFunction.getCallTargetStable()")
+        protected static Object directDispatch(VirtualFrame frame, SLFunction function, Object[] arguments, //
+                        @Cached("function") SLFunction cachedFunction, //
+                        @Cached("create(cachedFunction.getCallTarget())") DirectCallNode callNode) {
+            return callNode.call(frame, arguments);
+        }
+
+        @Specialization(contains = "directDispatch")
+        protected static Object indirectDispatch(VirtualFrame frame, SLFunction function, Object[] arguments, //
+                        @Cached("create()") IndirectCallNode callNode) {
+            return callNode.call(frame, function.getCallTarget(), arguments);
+        }
+    }
+
+    public static final class SLFunction {
+
+        private CallTarget callTarget;
+        private final CyclicAssumption callTargetStable;
+
+        protected SLFunction(String name) {
+            this.callTargetStable = new CyclicAssumption(name);
+        }
+
+        protected void setCallTarget(CallTarget callTarget) {
+            this.callTarget = callTarget;
+            this.callTargetStable.invalidate();
+        }
+
+        public CallTarget getCallTarget() {
+            return callTarget;
+        }
+
+        public Assumption getCallTargetStable() {
+            return callTargetStable.getAssumption();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Cached.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,235 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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;
+
+import java.lang.annotation.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.utilities.*;
+
+/**
+ * <p>
+ * A parameter annotated with {@link Cached} in a {@link Specialization} refers to a <b>cached</b>
+ * value of a specialization instance. A cached parameter value is initialized once using the
+ * initializer expression at specialization instantiation. For each call of the specialization
+ * method the cached value is provided by using the annotated parameter from the method body. Cache
+ * initializers are potentially executed before guard expressions declared in
+ * {@link Specialization#guards()}.
+ * </p>
+ * <p>
+ * A typical specialization may define multiple dynamic and multiple cached parameters. Dynamic
+ * parameter values are typically provided by executing child nodes of the operation. Cached
+ * parameters are initialized and stored once per specialization instantiation. Cached parameters
+ * are always constant at compile time. You may verify this by invoking
+ * {@link CompilerAsserts#compilationConstant(Object)} on any cached parameter. For consistency
+ * between specialization declarations cached parameters must be declared last in a specialization
+ * method.
+ * </p>
+ * <p>
+ * The initializer expression of a cached parameter is defined using a subset of Java. This subset
+ * includes field/parameter accesses, function calls, type exact infix comparisons (==, !=, <, <=,
+ * >, >=) and integer literals. The return type of the initializer expression must be assignable to
+ * the parameter type. If the annotated parameter type is derived from {@link Node} then the
+ * {@link Node} instance is allowed to use the {@link Node#replace(Node)} method to replace itself.
+ * Bound elements without receivers are resolved using the following order:
+ * <ol>
+ * <li>Dynamic and cached parameters of the enclosing specialization.</li>
+ * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+ * <li>Public constructors of the type of the annotated parameter using the <code>new</code> keyword
+ * as method name.</li>
+ * <li>Public and static methods or fields of the type of the annotated parameter.</li>
+ * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+ * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+ * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+ * </ol>
+ *
+ * The following examples explain the intended use of the {@link Cached} annotation. All of the
+ * examples have to be enclosed in the following node declaration:
+ * </p>
+ *
+ * <pre>
+ * @NodeChild("operand")
+ * abstract TestNode extends Node {
+ *   abstract void execute(Object operandValue);
+ *   // ... example here ...
+ * }
+ * </pre>
+ *
+ * <ol>
+ * <li>
+ * This example defines one dynamic and one cached parameter. The operand parameter is representing
+ * the dynamic value of the operand while the cachedOperand is initialized once at first execution
+ * of the specialization (specialization instantiation time).
+ *
+ * <pre>
+ *  &#064;Specialization
+ *  void doCached(int operand, @Local(&quot;operand&quot;) int cachedOperand) {
+ *      CompilerAsserts.compilationConstant(cachedOperand);
+ *      ...
+ *  }
+ *
+ *  Example executions:
+ *  execute(1) => doCached(1, 1) // new instantiation, localOperand is bound to 1
+ *  execute(0) => doCached(0, 1)
+ *  execute(2) => doCached(2, 1)
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * We extend the previous example by a guard for the cachedOperand value to be equal to the dynamic
+ * operand value. This specifies that the specialization is instantiated for each individual operand
+ * value that is provided. There are a lot of individual <code>int</code> values and for each
+ * individual <code>int</code> value a new specialization would get instantiated. The
+ * {@link Specialization#limit()} property defines a limit for the number of specializations that
+ * can get instantiated. If the specialization instantiation limit is reached then no further
+ * specializations are instantiated. Like for other specializations if there are no more
+ * specializations defined an {@link UnsupportedSpecializationException} is thrown. The default
+ * specialization instantiation limit is <code>3</code>.
+ *
+ * <pre>
+ * &#064;Specialization(guards = &quot;==(operand, cachedOperand)&quot;)
+ * void doCached(int operand, @Cached(&quot;operand&quot;) int cachedOperand) {
+ *    CompilerAsserts.compilationConstant(cachedOperand);
+ *    ...
+ * }
+ *
+ * Example executions:
+ * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0
+ * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1
+ * execute(1) => doCached(1, 1)
+ * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2
+ * execute(3) => throws UnsupportedSpecializationException // instantiation limit overflows
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * To handle the limit overflow we extend our example by an additional specialization named
+ * <code>doNormal</code>. This specialization has the same type restrictions but does not have local
+ * state nor the operand identity guard. It is also declared after <code>doCached</code> therefore
+ * it is only instantiated if the limit of the <code>doCached</code> specialization has been
+ * reached. In other words <code>doNormal</code> is more generic than <code>doCached</code> . The
+ * <code>doNormal</code> specialization uses <code>contains=&quot;doCached&quot;</code> to specify
+ * that all instantiations of <code>doCached</code> get removed if <code>doNormal</code> is
+ * instantiated. Alternatively if the <code>contains</code> relation is omitted then all
+ * <code>doCached</code> instances remain but no new instances are created.
+ *
+ * <code>
+ * &#064;Specialization(guards = &quot;==(operand, cachedOperand)&quot;)
+ * void doCached(int operand, @Cached(&quot;operand&quot;) int cachedOperand) {
+ *    CompilerAsserts.compilationConstant(cachedOperand);
+ *    ...
+ * }
+ *
+ * &#064;Specialization(contains = &quot;doCached&quot;)
+ * void doNormal(int operand) {...}
+ *
+ * Example executions with contains = &quot;doCached&quot;:
+ * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0
+ * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1
+ * execute(1) => doCached(1, 1)
+ * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2
+ * execute(3) => doNormal(3)    // new instantiation of doNormal due to limit overflow; doCached gets removed.
+ * execute(1) => doNormal(1)
+ *
+ * Example executions without contains = &quot;doCached&quot;:
+ * execute(0) => doCached(0, 0) // new instantiation, cachedOperand is bound to 0
+ * execute(1) => doCached(1, 1) // new instantiation, cachedOperand is bound to 1
+ * execute(1) => doCached(1, 1)
+ * execute(2) => doCached(2, 2) // new instantiation, cachedOperand is bound to 2
+ * execute(3) => doNormal(3)    // new instantiation of doNormal due to limit overflow
+ * execute(1) => doCached(1, 1)
+ *
+ * </code>
+ *
+ * </li>
+ * <li>
+ * This next example shows how methods from the enclosing node can be used to initialize cached
+ * parameters. Please note that the visibility of transformLocal must not be <code>private</code>.
+ *
+ * <pre>
+ * &#064;Specialization
+ * void s(int operand, @Cached(&quot;transformLocal(operand)&quot;) int cachedOperand) {
+ * }
+ *
+ * int transformLocal(int operand) {
+ *     return operand & 0x42;
+ * }
+ *
+ * </li>
+ * </pre>
+ * <li>
+ * The <code>new</code> keyword can be used to initialize a cached parameter using a constructor of
+ * the parameter type.
+ *
+ * <pre>
+ * &#064;Specialization
+ * void s(Object operand, @Cached(&quot;new()&quot;) OtherNode someNode) {
+ *     someNode.execute(operand);
+ * }
+ *
+ * static class OtherNode extends Node {
+ *
+ *     public String execute(Object value) {
+ *         throw new UnsupportedOperationException();
+ *     }
+ * }
+ *
+ * </pre>
+ *
+ * </li>
+ * <li>
+ * Java types without public constructor but with a static factory methods can be initialized by
+ * just referencing its static factory method and its parameters. In this case
+ * {@link BranchProfile#create()} is used to instantiate the {@link BranchProfile} instance.
+ *
+ * <pre>
+ * &#064;Specialization
+ * void s(int operand, @Local(&quot;create()&quot;) BranchProfile profile) {
+ * }
+ * </pre>
+ *
+ * </li>
+ * </ol>
+ *
+ * @see Specialization#guards()
+ * @see Specialization#contains()
+ * @see Specialization#limit()
+ * @see ImportStatic
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER})
+public @interface Cached {
+
+    /**
+     * Defines the initializer expression of the cached parameter value.
+     *
+     * @see Cached
+     */
+    String value();
+
+}
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Implies.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Implies.java	Thu Feb 12 04:01:46 2015 +0100
@@ -26,11 +26,14 @@
 
 import java.lang.annotation.*;
 
-/*
+/**
  * Experimental API.
+ * 
+ * @deprecated annotation has no effect anymore.
  */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.METHOD})
+@Deprecated
 public @interface Implies {
 
     String[] value();
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ImportGuards.java	Thu Feb 12 03:42:51 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +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.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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;
-
-import java.lang.annotation.*;
-
-/**
- * Imports all public static methods usable as guards for {@link Specialization} annotations to the
- * current class. Using this annotation common guards can be shared across nodes. Imported guards
- * are derived from super classes. Guards declared in the node type hierarchy are always preferred
- * to imported guards. Imported guards for a more concrete type are preferred to guards imported in
- * the base class.
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface ImportGuards {
-
-    Class<?>[] value();
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ImportStatic.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,44 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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;
+
+import java.lang.annotation.*;
+
+/**
+ * Imports all <code>public</code> and <code>static</code> methods and fields of the provided
+ * classes for the use in DSL expressions of the annotated class or its subclasses.
+ *
+ * @see Specialization#guards()
+ * @see Specialization#assumptions()
+ * @see Specialization#limit()
+ * @see Cached
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface ImportStatic {
+
+    Class<?>[] value();
+
+}
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeAssumptions.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeAssumptions.java	Thu Feb 12 04:01:46 2015 +0100
@@ -26,13 +26,14 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.truffle.api.*;
+
 /**
- * Declares one or multiple assumptions for use inside a source code generation enabled node.
- * Declared assumptions must be passed to the {@link NodeFactory#createNode(Object...)} method as
- * parameters.
+ * @deprecated use {@link NodeField} with type {@link Assumption} instead.
  */
 @Retention(RetentionPolicy.CLASS)
 @Target({ElementType.TYPE})
+@Deprecated
 public @interface NodeAssumptions {
 
     String[] value();
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Thu Feb 12 04:01:46 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -26,6 +26,91 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * <p>
+ * Defines a method of a node subclass to represent one specialization of an operation. Multiple
+ * specializations can be defined in a node representing an operation. A specialization defines
+ * which kind of input is expected using the method signature and the annotation attributes. The
+ * specialized semantics of the operation are defined using the body of the annotated Java method. A
+ * specialization method must be declared in a class that is derived from {@link Node} that
+ * references a {@link TypeSystem}. At least one specialization must be defined per operation. If no
+ * specialization is valid for the given set of input values then an
+ * {@link UnsupportedSpecializationException} is thrown instead of invoking any specialization
+ * method.
+ * </p>
+ * <p>
+ * A specialization must have at least as many parameters as there are {@link NodeChild} annotations
+ * declared for the enclosing operation node. These parameters are declared in the same order as the
+ * {@link NodeChild} annotations (linear execution order). We call such parameters dynamic input
+ * parameters. Every specialization that is declared within an operation must have an equal number
+ * of dynamic input parameters.
+ * </p>
+ * <p>
+ * The supported kind of input values for a specialization are declared using guards. A
+ * specialization may provide declarative specifications for four kinds of guards:
+ * <ul>
+ * <li><b>Type guards</b> optimistically assume the type of an input value. A value that matches the
+ * type is cast to its expected type automatically. Type guards are modeled using the parameter type
+ * of the specialization method. Types used for type guards must be defined in the
+ * {@link TypeSystem}. If the type of the parameter is {@link Object} then no type guard is used for
+ * the dynamic input parameter.</li>
+ *
+ * <li><b>Expression guards</b> optimistically assume the return value of a user-defined expression
+ * to be <code>true</code>. Expression guards are modeled using Java expressions that return a
+ * <code>boolean</code> value. If the guard expression returns <code>false</code>, the
+ * specialization is no longer applicable and the operation is re-specialized. Guard expressions are
+ * declared using the {@link #guards()} attribute.</li>
+ *
+ * <li><b>Event guards</b> trigger re-specialization in case an exception is thrown in the
+ * specialization body. The {@link #rewriteOn()} attribute can be used to declare a list of such
+ * exceptions. Guards of this kind are useful to avoid calculating a value twice when it is used in
+ * the guard and its specialization.</li>
+ *
+ * <li><b>Assumption guards</b> optimistically assume that the state of an {@link Assumption}
+ * remains <code>true</code>. Assumptions can be assigned to specializations using the
+ * {@link #assumptions()} attribute.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The enclosing {@link Node} of a specialization method must have at least one <code>public</code>
+ * and non-<code>final</code> execute method. An execute method is a method that starts with
+ * 'execute'. If all execute methods declare the first parameter type as {@link Frame},
+ * {@link VirtualFrame} or {@link MaterializedFrame} then the same frame type can be used as
+ * optional first parameter of the specialization. This parameter does not count to the number of
+ * dynamic parameters.
+ * </p>
+ * <p>
+ * A specialization method may declare multiple parameters annotated with {@link Cached}. Cached
+ * parameters are initialized and stored once per specialization instantiation. For consistency
+ * between specialization declarations cached parameters must be declared last in a specialization
+ * method.
+ * </p>
+ * <p>
+ * If the operation is re-specialized or if it is executed for the first time then all declared
+ * specializations of the operation are tried in declaration order until the guards of the first
+ * specialization accepts the current input values. The new specialization is then added to the
+ * chain of current specialization instances which might consist of one (monomorph) or multiple
+ * instances (polymorph). If an assumption of an instantiated specialization is violated then
+ * re-specialization is triggered again.
+ * </p>
+ * <p>
+ * With guards in combination with cached parameters it is possible that multiple instances of the
+ * same specialization are created. The {@link #limit()} attribute can be used to limit the number
+ * of instantiations per specialization.
+ * </p>
+ *
+ * @see NodeChild
+ * @see ShortCircuit
+ * @see Fallback
+ * @see Cached
+ * @see TypeSystem
+ * @see TypeSystemReference
+ * @see UnsupportedSpecializationException
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.METHOD})
 public @interface Specialization {
@@ -36,39 +121,234 @@
     @Deprecated int DEFAULT_ORDER = -1;
 
     /**
-     * The order has no effect anymore. The declaration order specialization methods is used
-     * instead.
-     *
      * @deprecated use declaration order instead. Will get removed in the next release.
      */
     @Deprecated
     int order() default DEFAULT_ORDER;
 
     /**
-     * Inserts this and all specializations that are declared after this specialization before a
-     * specialization in the superclass. By default all specializations of the subclass are appended
-     * to the specializations of the superclass.
+     * References a specialization of a super class by its method name where this specialization is
+     * inserted before. The declaration order of a specialization is not usable for nodes where
+     * specializations are partly declared in the super class and partly declared in a derived
+     * class. By default all specializations declared in the derived class are appended to those in
+     * the super class. This attribute can be used to override the default behavior.
      */
     String insertBefore() default "";
 
+    /**
+     * <p>
+     * Declares an event guards that trigger re-specialization in case an exception is thrown in the
+     * specialization body. This attribute can be used to declare a list of such exceptions. Guards
+     * of this kind are useful to avoid calculating a value twice when it is used in the guard and
+     * its specialization.
+     * </p>
+     *
+     * <p>
+     * If an event guard exception is triggered then all instantiations of this specialization are
+     * removed. If one of theses exceptions is thrown once then no further instantiations of this
+     * specialization are going to be created for this node. A specialization that rewrites on an
+     * exception must ensure that no non-repeatable side-effect is caused until the rewrite is
+     * triggered.
+     * </p>
+     *
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * &#064;Specialization(rewriteOn = ArithmeticException.class)
+     * int doAddNoOverflow(int a, int b) {
+     *     return ExactMath.addExact(a, b);
+     * }
+     * &#064;Specialization
+     * long doAddWithOverflow(int a, int b) {
+     *     return a + b;
+     * }
+     * ...
+     * Example executions:
+     *   execute(Integer.MAX_VALUE - 1, 1) => doAddNoOverflow(Integer.MAX_VALUE - 1, 1)
+     *   execute(Integer.MAX_VALUE, 1)     => doAddNoOverflow(Integer.MAX_VALUE, 1)
+     *                                     => throws ArithmeticException
+     *                                     => doAddWithOverflow(Integer.MAX_VALUE, 1)
+     *   execute(Integer.MAX_VALUE - 1, 1) => doAddWithOverflow(Integer.MAX_VALUE - 1, 1)
+     * </pre>
+     *
+     * </p>
+     *
+     * @see ExactMath#addExact(int, int)
+     */
     Class<? extends Throwable>[] rewriteOn() default {};
 
     /**
-     * The contains attribute declares all specializations that are contained by this
-     * specialization. A containing specialization must be strictly generic as the contained
-     * specialization.
+     * <p>
+     * Declares other specializations of the same node to be contained by this specialization. Other
+     * specializations are references using their unique method name. If this specialization is
+     * instantiated then all contained specialization instances are removed and never instantiated
+     * again for this node instance. Therefore this specialization should handle strictly more
+     * inputs than which were handled by the contained specialization, otherwise the removal of the
+     * contained specialization will lead to unspecialized types of input values. The contains
+     * declaration is transitive for multiple involved specializations.
+     * </p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * &#064;Specialization(guards = "b == 2")
+     * void doDivPowerTwo(int a, int b) {
+     *     return a >> 1;
+     * }
+     * &#064;Specialization(contains ="doDivPowerTwo", guards = "b > 0")
+     * void doDivPositive(int a, int b) {
+     *     return a / b;
+     * }
+     * ...
+     * Example executions with contains="doDivPowerTwo":
+     *   execute(4, 2) => doDivPowerTwo(4, 2)
+     *   execute(9, 3) => doDivPositive(9, 3) // doDivPowerTwo instances get removed
+     *   execute(4, 2) => doDivPositive(4, 2)
+     * Same executions without contains="doDivPowerTwo"
+     *   execute(4, 2) => doDivPowerTwo(4, 2)
+     *   execute(9, 3) => doDivPositive(9, 3)
+     *   execute(4, 2) => doDivPowerTwo(4, 2)
+     * </pre>
+     *
+     * </p>
+     *
+     * @see #guards()
      */
     String[] contains() default {};
 
+    /**
+     * <p>
+     * Declares <code>boolean</code> expressions that define whether or not input values are
+     * applicable to this specialization instance. Guard expressions must always return the same
+     * result for each combination of the enclosing node instance and the bound input values.
+     * </p>
+     * <p>
+     * If a guard expression does not bind any dynamic input parameters then the DSL assumes that
+     * the result will not change for this node after specialization instantiation. The DSL asserts
+     * this assumption if assertions are enabled (-ea).
+     * </p>
+     * <p>
+     * Guard expressions are defined using a subset of Java. This subset includes field/parameter
+     * accesses, function calls, type exact infix comparisons (==, !=, <, <=, >, >=), logical
+     * negation (!), logical disjunction (||) and integer literals. The return type of guard
+     * expressions must be <code>boolean</code>. Bound elements without receivers are resolved using
+     * the following order:
+     * <ol>
+     * <li>Dynamic and cached parameters of the enclosing specialization.</li>
+     * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+     * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+     * </ol>
+     * </p>
+     * <p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * static boolean acceptOperand(int operand) {
+     *     assert operand <= 42;
+     *     return operand & 1 == 1;
+     * }
+     * &#064;Specialization(guards = {"operand <= 42", "acceptOperand(operand)"})
+     * void doSpecialization(int operand) {...}
+     * </pre>
+     *
+     * </p>
+     *
+     * @see Cached
+     * @see ImportStatic
+     */
     String[] guards() default {};
 
     /**
-     * Defines the assumptions to check for this specialization. When the specialization method is
-     * invoked it is guaranteed that these assumptions still hold. It is not guaranteed that they
-     * are checked before the {@link #guards()} methods. They may be checked before after or in
-     * between {@link #guards()}. To declare assumptions use the {@link NodeAssumptions} annotation
-     * at class level.
+     * <p>
+     * Declares assumption guards that optimistically assume that the state of an {@link Assumption}
+     * remains valid. Assumption expressions are cached once per specialization instantiation. If
+     * one of the returned assumptions gets invalidated then the specialization instance is removed.
+     * If the assumption expression returns an array of assumptions then all assumptions of the
+     * array are checked. This is limited to one-dimensional arrays.
+     * </p>
+     * <p>
+     * Assumption expressions are defined using a subset of Java. This subset includes
+     * field/parameter accesses, function calls, type exact infix comparisons (==, !=, <, <=, >,
+     * >=), logical negation (!), logical disjunction (||) and integer literals. The return type of
+     * the expression must be {@link Assumption} or an array of {@link Assumption} instances.
+     * Assumption expressions are not allowed to bind to dynamic parameter values of the
+     * specialization. Bound elements without receivers are resolved using the following order:
+     * <ol>
+     * <li>Cached parameters of the enclosing specialization.</li>
+     * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+     * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * static abstract class DynamicObject() {
+     *      abstract Shape getShape();
+     *      ...
+     * }
+     * static abstract class Shape() {
+     *      abstract Assumption getUnmodifiedAssuption();
+     *      ...
+     * }
+     * &#064;Specialization(guards = "operand.getShape() == cachedShape", assumptions = "cachedShape.getUnmodifiedAssumption()")
+     * void doAssumeUnmodifiedShape(DynamicObject operand, @Cached("operand.getShape()") Shape cachedShape) {...}
+     * </pre>
+     *
+     * </p>
+     *
+     * @see Cached
+     * @see ImportStatic
      */
     String[] assumptions() default {};
 
+    /**
+     * <p>
+     * Declares the expression that limits the number of specialization instantiations. The default
+     * limit for specialization instantiations is defined as <code>"3"</code>. If the limit is
+     * exceeded no more instantiations of the enclosing specialization method are created. Please
+     * note that the existing specialization instantiations are <b>not</b> removed from the
+     * specialization chain. You can use {@link #contains()} to remove unnecessary specializations
+     * instances.
+     * </p>
+     * <p>
+     * The limit expression is defined using a subset of Java. This subset includes field/parameter
+     * accesses, function calls, type exact infix comparisons (==, !=, <, <=, >, >=), logical
+     * negation (!), logical disjunction (||) and integer literals. The return type of the limit
+     * expression must be <code>int</code>. Limit expressions are not allowed to bind to dynamic
+     * parameter values of the specialization. Bound elements without receivers are resolved using
+     * the following order:
+     * <ol>
+     * <li>Cached parameters of the enclosing specialization.</li>
+     * <li>Fields defined using {@link NodeField} for the enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of enclosing node.</li>
+     * <li>Non-private, static or virtual methods or fields of super types of the enclosing node.</li>
+     * <li>Public and static methods or fields imported using {@link ImportStatic}.</li>
+     * </ol>
+     * </p>
+     *
+     * <p>
+     * <b>Example usage:</b>
+     *
+     * <pre>
+     * static int getCacheLimit() {
+     *     return Integer.parseInt(System.getProperty("language.cacheLimit"));
+     * }
+     * &#064;Specialization(guards = "operand == cachedOperand", limit = "getCacheLimit()")
+     * void doCached(Object operand, @Cached("operand") Object cachedOperand) {...}
+     * </pre>
+     *
+     * </p>
+     *
+     * @see #guards()
+     * @see #contains()
+     * @see Cached
+     * @see ImportStatic
+     */
+    String limit() default "";
+
 }
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java	Thu Feb 12 04:01:46 2015 +0100
@@ -34,8 +34,9 @@
 @Target({ElementType.TYPE})
 public @interface DSLOptions {
 
-    /** Enable the new DSL generation layout. */
-    boolean useNewLayout() default false;
+    /** Flag has no effect anymore. Is going to be removed soon. */
+    @Deprecated
+    boolean useNewLayout() default true;
 
     /**
      * Lazy class loading ensures that all generated specialization classes are loaded lazily.
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -25,6 +25,7 @@
 package com.oracle.truffle.api.dsl.internal;
 
 import java.lang.reflect.*;
+import java.util.*;
 import java.util.concurrent.*;
 
 import com.oracle.truffle.api.*;
@@ -64,6 +65,14 @@
         return NodeCost.NONE;
     }
 
+    public void reset() {
+        SpecializationNode start = findStart();
+        SpecializationNode end = findEnd();
+        if (start != end) {
+            start.replace(end, "reset specialization");
+        }
+    }
+
     public static Node updateRoot(Node node) {
         updateRootImpl(((SpecializedNode) node).getSpecializationNode(), node);
         return node;
@@ -86,7 +95,7 @@
     protected final SpecializationNode polymorphicMerge(SpecializationNode newNode) {
         SpecializationNode merged = next.merge(newNode);
         if (merged == newNode && !isSame(newNode) && count() <= 2) {
-            return removeSame(new RewriteEvent0(findParentNode(), "merged polymorphic to monomorphic"));
+            return removeSame(new RewriteEvent0(findRoot(), "merged polymorphic to monomorphic"));
         }
         return merged;
     }
@@ -112,6 +121,22 @@
         return next != null ? next.merge(newNode) : newNode;
     }
 
+    protected SpecializationNode mergeNoSame(SpecializationNode newNode) {
+        return next != null ? next.merge(newNode) : newNode;
+    }
+
+    protected final int countSame(SpecializationNode node) {
+        return findStart().countSameImpl(node);
+    }
+
+    private int countSameImpl(SpecializationNode node) {
+        if (next != null) {
+            return next.countSameImpl(node) + (isSame(node) ? 1 : 0);
+        } else {
+            return 0;
+        }
+    }
+
     @Override
     public final boolean equals(Object obj) {
         if (obj instanceof SpecializationNode) {
@@ -133,10 +158,51 @@
         return next != null ? next.count() + 1 : 1;
     }
 
+    private SpecializationNode findEnd() {
+        SpecializationNode node = this;
+        while (node.next != null) {
+            node = node.next;
+        }
+        return node;
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame) {
+        return removeThisImpl(reason).acceptAndExecute(frame);
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame, Object o1) {
+        return removeThisImpl(reason).acceptAndExecute(frame, o1);
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2) {
+        return removeThisImpl(reason).acceptAndExecute(frame, o1, o2);
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2, Object o3) {
+        return removeThisImpl(reason).acceptAndExecute(frame, o1, o2, o3);
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2, Object o3, Object o4) {
+        return removeThisImpl(reason).acceptAndExecute(frame, o1, o2, o3, o4);
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) {
+        return removeThisImpl(reason).acceptAndExecute(frame, o1, o2, o3, o4, o5);
+    }
+
+    protected final Object removeThis(final CharSequence reason, Frame frame, Object... args) {
+        return removeThisImpl(reason).acceptAndExecute(frame, args);
+    }
+
+    private SpecializationNode removeThisImpl(final CharSequence reason) {
+        this.replace(this.next, reason);
+        return findEnd().findStart();
+    }
+
     protected final SpecializationNode removeSame(final CharSequence reason) {
         return atomic(new Callable<SpecializationNode>() {
             public SpecializationNode call() throws Exception {
-                return removeImpl(SpecializationNode.this, reason);
+                return removeSameImpl(SpecializationNode.this, reason);
             }
         });
     }
@@ -156,11 +222,11 @@
         return node;
     }
 
-    private Node findParentNode() {
+    private Node findRoot() {
         return findStart().getParent();
     }
 
-    private SpecializationNode removeImpl(SpecializationNode toRemove, CharSequence reason) {
+    private SpecializationNode removeSameImpl(SpecializationNode toRemove, CharSequence reason) {
         SpecializationNode start = findStart();
         SpecializationNode current = start;
         while (current != null) {
@@ -172,7 +238,7 @@
             }
             current = current.next;
         }
-        return start;
+        return findEnd().findStart();
     }
 
     public Object acceptAndExecute(Frame frame) {
@@ -248,7 +314,7 @@
         if (nextSpecialization == null) {
             return unsupported(frame);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEvent0(findParentNode(), "inserted new specialization")).acceptAndExecute(frame);
+        return insertSpecialization(nextSpecialization, new RewriteEvent0(findRoot(), "inserted new specialization")).acceptAndExecute(frame);
     }
 
     protected final Object uninitialized(Frame frame, Object o1) {
@@ -260,7 +326,7 @@
         if (nextSpecialization == null) {
             return unsupported(frame, o1);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEvent1(findParentNode(), "inserted new specialization", o1)).acceptAndExecute(frame, o1);
+        return insertSpecialization(nextSpecialization, new RewriteEvent1(findRoot(), "inserted new specialization", o1)).acceptAndExecute(frame, o1);
     }
 
     protected final Object uninitialized(Frame frame, Object o1, Object o2) {
@@ -272,7 +338,7 @@
         if (nextSpecialization == null) {
             return unsupported(frame, o1, o2);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEvent2(findParentNode(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2);
+        return insertSpecialization(nextSpecialization, new RewriteEvent2(findRoot(), "inserted new specialization", o1, o2)).acceptAndExecute(frame, o1, o2);
     }
 
     protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3) {
@@ -284,7 +350,7 @@
         if (nextSpecialization == null) {
             return unsupported(frame, o1, o2, o3);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEvent3(findParentNode(), "inserted new specialization", o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3);
+        return insertSpecialization(nextSpecialization, new RewriteEvent3(findRoot(), "inserted new specialization", o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3);
     }
 
     protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4) {
@@ -296,7 +362,7 @@
         if (nextSpecialization == null) {
             return unsupported(frame, o1, o2, o3, o4);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEvent4(findParentNode(), "inserts new specialization", o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4);
+        return insertSpecialization(nextSpecialization, new RewriteEvent4(findRoot(), "inserts new specialization", o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4);
     }
 
     protected final Object uninitialized(Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) {
@@ -308,7 +374,7 @@
         if (nextSpecialization == null) {
             unsupported(frame, o1, o2, o3, o4, o5);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEventN(findParentNode(), "inserts new specialization", o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5);
+        return insertSpecialization(nextSpecialization, new RewriteEventN(findRoot(), "inserts new specialization", o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5);
     }
 
     protected final Object uninitialized(Frame frame, Object... args) {
@@ -320,7 +386,7 @@
         if (nextSpecialization == null) {
             unsupported(frame, args);
         }
-        return insertSpecialization(nextSpecialization, new RewriteEventN(findParentNode(), "inserts new specialization", args)).acceptAndExecute(frame, args);
+        return insertSpecialization(nextSpecialization, new RewriteEventN(findRoot(), "inserts new specialization", args)).acceptAndExecute(frame, args);
     }
 
     private boolean needsPolymorphic() {
@@ -328,59 +394,59 @@
     }
 
     protected final Object remove(String reason, Frame frame) {
-        return removeSame(new RewriteEvent0(findParentNode(), reason)).acceptAndExecute(frame);
+        return removeSame(new RewriteEvent0(findRoot(), reason)).acceptAndExecute(frame);
     }
 
     protected final Object remove(String reason, Frame frame, Object o1) {
-        return removeSame(new RewriteEvent1(findParentNode(), reason, o1)).acceptAndExecute(frame, o1);
+        return removeSame(new RewriteEvent1(findRoot(), reason, o1)).acceptAndExecute(frame, o1);
     }
 
     protected final Object remove(String reason, Frame frame, Object o1, Object o2) {
-        return removeSame(new RewriteEvent2(findParentNode(), reason, o1, o2)).acceptAndExecute(frame, o1, o2);
+        return removeSame(new RewriteEvent2(findRoot(), reason, o1, o2)).acceptAndExecute(frame, o1, o2);
     }
 
     protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3) {
-        return removeSame(new RewriteEvent3(findParentNode(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3);
+        return removeSame(new RewriteEvent3(findRoot(), reason, o1, o2, o3)).acceptAndExecute(frame, o1, o2, o3);
     }
 
     protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3, Object o4) {
-        return removeSame(new RewriteEvent4(findParentNode(), reason, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4);
+        return removeSame(new RewriteEvent4(findRoot(), reason, o1, o2, o3, o4)).acceptAndExecute(frame, o1, o2, o3, o4);
     }
 
     protected final Object remove(String reason, Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) {
-        return removeSame(new RewriteEventN(findParentNode(), reason, o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5);
+        return removeSame(new RewriteEventN(findRoot(), reason, o1, o2, o3, o4, o5)).acceptAndExecute(frame, o1, o2, o3, o4, o5);
     }
 
     protected final Object remove(String reason, Frame frame, Object... args) {
-        return removeSame(new RewriteEventN(findParentNode(), reason, args)).acceptAndExecute(frame, args);
+        return removeSame(new RewriteEventN(findRoot(), reason, args)).acceptAndExecute(frame, args);
     }
 
     protected Object unsupported(Frame frame) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren());
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren());
     }
 
     protected Object unsupported(Frame frame, Object o1) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1);
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1);
     }
 
     protected Object unsupported(Frame frame, Object o1, Object o2) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2);
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2);
     }
 
     protected Object unsupported(Frame frame, Object o1, Object o2, Object o3) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3);
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2, o3);
     }
 
     protected Object unsupported(Frame frame, Object o1, Object o2, Object o3, Object o4) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3, o4);
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2, o3, o4);
     }
 
     protected Object unsupported(Frame frame, Object o1, Object o2, Object o3, Object o4, Object o5) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), o1, o2, o3, o4, o5);
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), o1, o2, o3, o4, o5);
     }
 
     protected Object unsupported(Frame frame, Object... args) {
-        throw new UnsupportedSpecializationException(findParentNode(), getSuppliedChildren(), args);
+        throw new UnsupportedSpecializationException(findRoot(), getSuppliedChildren(), args);
     }
 
     private SpecializationNode insertSpecialization(final SpecializationNode generated, final CharSequence message) {
@@ -412,8 +478,8 @@
             return insertBefore(insertBefore, generated, message);
         } else {
             // existing node
-            merged.replace(merged, new RewriteEvent0(merged.findParentNode(), "merged specialization"));
-            return merged;
+            merged.replace(merged, new RewriteEvent0(merged.findRoot(), "merged specialization"));
+            return start;
         }
     }
 
@@ -438,7 +504,7 @@
 
         appendFields(b, clazz);
         if (next != null) {
-            b.append(" -> ").append(next.toString());
+            b.append("\n -> ").append(next.toString());
         }
         return b.toString();
     }
@@ -449,25 +515,69 @@
             return;
         }
         b.append("(");
+        String sep = "";
         for (Field field : fields) {
             if (Modifier.isStatic(field.getModifiers())) {
                 continue;
             }
+            b.append(sep);
             String name = field.getName();
             if (name.equals("root")) {
                 continue;
             }
             b.append(field.getName());
+            b.append(" = ");
             try {
                 field.setAccessible(true);
-                b.append(field.get(this));
+                Object value = field.get(this);
+                if (value instanceof Object[]) {
+                    b.append(Arrays.toString((Object[]) field.get(this)));
+                } else {
+                    b.append(field.get(this));
+                }
             } catch (IllegalArgumentException e) {
                 b.append(e.toString());
             } catch (IllegalAccessException e) {
                 b.append(e.toString());
             }
+            sep = ", ";
         }
         b.append(")");
     }
 
+    // utilities for generated code
+    protected static void check(Assumption assumption) throws InvalidAssumptionException {
+        if (assumption != null) {
+            assumption.check();
+        }
+    }
+
+    @ExplodeLoop
+    protected static void check(Assumption[] assumptions) throws InvalidAssumptionException {
+        if (assumptions != null) {
+            CompilerAsserts.compilationConstant(assumptions.length);
+            for (Assumption assumption : assumptions) {
+                check(assumption);
+            }
+        }
+    }
+
+    protected static boolean isValid(Assumption assumption) {
+        if (assumption != null) {
+            return assumption.isValid();
+        }
+        return true;
+    }
+
+    protected static boolean isValid(Assumption[] assumptions) {
+        if (assumptions != null) {
+            for (Assumption assumption : assumptions) {
+                if (!isValid(assumption)) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
 }
--- a/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Thu Feb 12 04:01:46 2015 +0100
@@ -198,6 +198,11 @@
     <property name="checkFormat" value=".*Header"/>
     <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable header checks"/>
   </module>
+  <module name="SuppressionCommentFilter">
+    <property name="offCommentFormat" value="CheckStyle: start generated"/>
+    <property name="onCommentFormat" value="CheckStyle: stop generated"/>
+    <property name="checkFormat" value=".*Name|.*LineLength"/>
+  </module>
   <module name="RegexpSingleline">
     <property name="format" value="System\.(out|err)\.print"/>
     <property name="fileExtensions" value="java"/>
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -181,4 +181,8 @@
         return String.format("%s(target=%s)", getClass().getSimpleName(), getCurrentCallTarget());
     }
 
+    public static DirectCallNode create(CallTarget target) {
+        return Truffle.getRuntime().createDirectCallNode(target);
+    }
+
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -48,4 +48,8 @@
      */
     public abstract Object call(VirtualFrame frame, CallTarget target, Object[] arguments);
 
+    public static IndirectCallNode create() {
+        return Truffle.getRuntime().createIndirectCallNode();
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Thu Feb 12 04:01:46 2015 +0100
@@ -44,8 +44,6 @@
  */
 public final class TruffleTypes {
 
-    public static final String OPTION_DETAILED_REWRITE_REASONS = "DetailedRewriteReasons";
-
     private final DeclaredType node;
     private final ArrayType nodeArray;
     private final TypeMirror unexpectedValueException;
@@ -68,7 +66,6 @@
     private final DeclaredType nodeFactory;
     private final DeclaredType nodeFactoryBase;
     private final DeclaredType dslMetadata;
-    private final DeclaredType implies;
     private final DeclaredType generateNodeFactory;
     private final TypeElement expectError;
 
@@ -97,7 +94,6 @@
         nodeFactory = getRequired(context, NodeFactory.class);
         nodeFactoryBase = getRequired(context, NodeFactoryBase.class);
         dslMetadata = getRequired(context, DSLMetadata.class);
-        implies = getRequired(context, Implies.class);
         expectError = (TypeElement) getRequired(context, ExpectError.class).asElement();
         generateNodeFactory = getRequired(context, GenerateNodeFactory.class);
     }
@@ -106,10 +102,6 @@
         return generateNodeFactory;
     }
 
-    public DeclaredType getImplies() {
-        return implies;
-    }
-
     public DeclaredType getDslMetadata() {
         return dslMetadata;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Copyright.frame	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+// The content of this file is automatically generated. DO NOT EDIT.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpression.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,413 @@
+/*
+ * 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.dsl.processor.expression;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+public abstract class DSLExpression {
+
+    private TypeMirror resolvedTargetType;
+
+    private DSLExpression() {
+    }
+
+    public static DSLExpression parse(String input) {
+        return Parser.parse(input);
+    }
+
+    public final Set<VariableElement> findBoundVariableElements() {
+        final Set<VariableElement> variables = new HashSet<>();
+        this.accept(new AbstractDSLExpressionVisitor() {
+
+            @Override
+            public void visitVariable(Variable variable) {
+                if (variable.getReceiver() == null) {
+                    variables.add(variable.getResolvedVariable());
+                }
+            }
+
+        });
+        return variables;
+    }
+
+    public final Set<Variable> findBoundVariables() {
+        final Set<Variable> variables = new HashSet<>();
+        this.accept(new AbstractDSLExpressionVisitor() {
+
+            @Override
+            public void visitVariable(Variable variable) {
+                if (variable.getReceiver() == null) {
+                    variables.add(variable);
+                }
+            }
+
+        });
+        return variables;
+    }
+
+    public void setResolvedTargetType(TypeMirror resolvedTargetType) {
+        this.resolvedTargetType = resolvedTargetType;
+    }
+
+    public TypeMirror getResolvedTargetType() {
+        return resolvedTargetType;
+    }
+
+    public abstract TypeMirror getResolvedType();
+
+    public abstract void accept(DSLExpressionVisitor visitor);
+
+    public static final class Negate extends DSLExpression {
+
+        private final DSLExpression receiver;
+
+        public Negate(DSLExpression receiver) {
+            this.receiver = receiver;
+        }
+
+        @Override
+        public void accept(DSLExpressionVisitor visitor) {
+            receiver.accept(visitor);
+            visitor.visitNegate(this);
+        }
+
+        public DSLExpression getReceiver() {
+            return receiver;
+        }
+
+        @Override
+        public TypeMirror getResolvedType() {
+            return receiver.getResolvedType();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Negate) {
+                return receiver.equals(((Negate) obj).receiver);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return receiver.hashCode();
+        }
+    }
+
+    public static final class Binary extends DSLExpression {
+
+        private final String operator;
+        private final DSLExpression left;
+        private final DSLExpression right;
+
+        private TypeMirror resolvedType;
+
+        public Binary(String operator, DSLExpression left, DSLExpression right) {
+            this.operator = operator;
+            this.left = left;
+            this.right = right;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Binary) {
+                Binary other = (Binary) obj;
+                return operator.equals(other.operator) && left.equals(other.left) && right.equals(other.right);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(operator, left, right);
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public DSLExpression getLeft() {
+            return left;
+        }
+
+        public DSLExpression getRight() {
+            return right;
+        }
+
+        @Override
+        public void accept(DSLExpressionVisitor visitor) {
+            left.accept(visitor);
+            right.accept(visitor);
+            visitor.visitBinary(this);
+        }
+
+        @Override
+        public TypeMirror getResolvedType() {
+            return resolvedType;
+        }
+
+        public void setResolvedType(TypeMirror resolvedType) {
+            this.resolvedType = resolvedType;
+        }
+
+        @Override
+        public String toString() {
+            return "Binary [left=" + left + ", operator=" + operator + ", right=" + right + ", resolvedType=" + resolvedType + "]";
+        }
+
+    }
+
+    public static final class Call extends DSLExpression {
+
+        private final DSLExpression receiver;
+        private final String name;
+        private final List<DSLExpression> parameters;
+
+        private ExecutableElement resolvedMethod;
+
+        public Call(DSLExpression receiver, String name, List<DSLExpression> parameters) {
+            this.receiver = receiver;
+            this.name = name;
+            this.parameters = parameters;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Call) {
+                Call other = (Call) obj;
+                return Objects.equals(receiver, other.receiver) && name.equals(other.name) && parameters.equals(other.parameters);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(receiver, name, parameters);
+        }
+
+        public DSLExpression getReceiver() {
+            return receiver;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public List<DSLExpression> getParameters() {
+            return parameters;
+        }
+
+        @Override
+        public void accept(DSLExpressionVisitor visitor) {
+            if (receiver != null) {
+                receiver.accept(visitor);
+            }
+            for (DSLExpression parameter : getParameters()) {
+                parameter.accept(visitor);
+            }
+            visitor.visitCall(this);
+        }
+
+        @Override
+        public TypeMirror getResolvedType() {
+            if (resolvedMethod == null) {
+                return null;
+            }
+            if (resolvedMethod.getKind() == ElementKind.CONSTRUCTOR) {
+                return resolvedMethod.getEnclosingElement().asType();
+            } else {
+                return resolvedMethod.getReturnType();
+            }
+        }
+
+        public ExecutableElement getResolvedMethod() {
+            return resolvedMethod;
+        }
+
+        public void setResolvedMethod(ExecutableElement resolvedMethod) {
+            this.resolvedMethod = resolvedMethod;
+        }
+
+        @Override
+        public String toString() {
+            return "Call [receiver=" + receiver + ", name=" + name + ", parameters=" + parameters + ", resolvedMethod=" + resolvedMethod + "]";
+        }
+
+    }
+
+    public static final class Variable extends DSLExpression {
+
+        private final DSLExpression receiver;
+        private final String name;
+
+        private VariableElement resolvedVariable;
+
+        public Variable(DSLExpression receiver, String name) {
+            this.receiver = receiver;
+            this.name = name;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof Variable) {
+                Variable other = (Variable) obj;
+                return Objects.equals(receiver, other.receiver) && name.equals(other.name);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(receiver, name);
+        }
+
+        public DSLExpression getReceiver() {
+            return receiver;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        @Override
+        public void accept(DSLExpressionVisitor visitor) {
+            if (receiver != null) {
+                receiver.accept(visitor);
+            }
+            visitor.visitVariable(this);
+        }
+
+        @Override
+        public TypeMirror getResolvedType() {
+            return resolvedVariable != null ? resolvedVariable.asType() : null;
+        }
+
+        public void setResolvedVariable(VariableElement resolvedVariable) {
+            this.resolvedVariable = resolvedVariable;
+        }
+
+        public VariableElement getResolvedVariable() {
+            return resolvedVariable;
+        }
+
+        @Override
+        public String toString() {
+            return "Variable [receiver=" + receiver + ", name=" + name + ", resolvedVariable=" + resolvedVariable + "]";
+        }
+
+    }
+
+    public static final class IntLiteral extends DSLExpression {
+
+        private final String literal;
+
+        private int resolvedValueInt;
+        private TypeMirror resolvedType;
+
+        public IntLiteral(String literal) {
+            this.literal = literal;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof IntLiteral) {
+                IntLiteral other = (IntLiteral) obj;
+                return resolvedValueInt == other.resolvedValueInt;
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return resolvedValueInt;
+        }
+
+        public String getLiteral() {
+            return literal;
+        }
+
+        public int getResolvedValueInt() {
+            return resolvedValueInt;
+        }
+
+        public void setResolvedValueInt(int resolved) {
+            this.resolvedValueInt = resolved;
+        }
+
+        @Override
+        public TypeMirror getResolvedType() {
+            return resolvedType;
+        }
+
+        public void setResolvedType(TypeMirror resolvedType) {
+            this.resolvedType = resolvedType;
+        }
+
+        @Override
+        public void accept(DSLExpressionVisitor visitor) {
+            visitor.visitIntLiteral(this);
+        }
+
+        @Override
+        public String toString() {
+            return "IntLiteral [literal=" + literal + ", resolvedValueInt=" + resolvedValueInt + ", resolvedType=" + resolvedType + "]";
+        }
+
+    }
+
+    public abstract class AbstractDSLExpressionVisitor implements DSLExpressionVisitor {
+
+        public void visitBinary(Binary binary) {
+        }
+
+        public void visitCall(Call binary) {
+        }
+
+        public void visitIntLiteral(IntLiteral binary) {
+        }
+
+        public void visitNegate(Negate negate) {
+        }
+
+        public void visitVariable(Variable binary) {
+        }
+    }
+
+    public interface DSLExpressionVisitor {
+
+        void visitBinary(Binary binary);
+
+        void visitNegate(Negate negate);
+
+        void visitCall(Call binary);
+
+        void visitVariable(Variable binary);
+
+        void visitIntLiteral(IntLiteral binary);
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/DSLExpressionResolver.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,235 @@
+/*
+ * 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.dsl.processor.expression;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+import javax.lang.model.util.*;
+
+import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Binary;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Call;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.DSLExpressionVisitor;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.IntLiteral;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Negate;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Variable;
+import com.oracle.truffle.dsl.processor.java.*;
+import com.oracle.truffle.dsl.processor.java.model.*;
+
+public class DSLExpressionResolver implements DSLExpressionVisitor {
+
+    private static final List<String> LOGIC_OPERATORS = Arrays.asList("||");
+    private static final List<String> COMPARABLE_OPERATORS = Arrays.asList("<", "<=", ">", ">=");
+    private static final List<String> IDENTITY_OPERATORS = Arrays.asList("==", "!=");
+    private static final String CONSTRUCTOR_KEYWORD = "new";
+
+    private final List<VariableElement> variables = new ArrayList<>();
+    private final List<ExecutableElement> methods = new ArrayList<>();
+    private final ProcessorContext context;
+
+    private DSLExpressionResolver(ProcessorContext context) {
+        this.context = context;
+    }
+
+    public DSLExpressionResolver(ProcessorContext context, List<? extends Element> lookupElements) {
+        this(context);
+        lookup(lookupElements);
+    }
+
+    public DSLExpressionResolver copy(List<? extends Element> prefixElements) {
+        DSLExpressionResolver resolver = new DSLExpressionResolver(context);
+        lookup(prefixElements);
+        resolver.variables.addAll(variables);
+        resolver.methods.addAll(methods);
+        return resolver;
+    }
+
+    private void lookup(List<? extends Element> lookupElements) {
+        variablesIn(variables, lookupElements, false);
+        methodsIn(lookupElements);
+    }
+
+    private void methodsIn(List<? extends Element> lookupElements) {
+        for (Element variable : lookupElements) {
+            ElementKind kind = variable.getKind();
+            if (kind == ElementKind.METHOD || kind == ElementKind.CONSTRUCTOR) {
+                methods.add((ExecutableElement) variable);
+            }
+        }
+    }
+
+    private static void variablesIn(List<VariableElement> variables, List<? extends Element> lookupElements, boolean publicOnly) {
+        for (Element variable : lookupElements) {
+            ElementKind kind = variable.getKind();
+            if (kind == ElementKind.LOCAL_VARIABLE || kind == ElementKind.PARAMETER || kind == ElementKind.FIELD || kind == ElementKind.ENUM_CONSTANT) {
+                VariableElement variableElement = (VariableElement) variable;
+                if (!publicOnly || variableElement.getModifiers().contains(Modifier.PUBLIC)) {
+                    variables.add(variableElement);
+                }
+            }
+        }
+    }
+
+    private static String getMethodName(ExecutableElement method) {
+        if (method.getKind() == ElementKind.CONSTRUCTOR) {
+            return CONSTRUCTOR_KEYWORD;
+        } else {
+            return method.getSimpleName().toString();
+        }
+    }
+
+    public void visitBinary(Binary binary) {
+        String operator = binary.getOperator();
+        TypeMirror leftType = binary.getLeft().getResolvedType();
+        TypeMirror rightType = binary.getRight().getResolvedType();
+        if (!ElementUtils.typeEquals(leftType, rightType)) {
+            throw new InvalidExpressionException(String.format("Incompatible operand types %s and %s.", ElementUtils.getSimpleName(leftType), ElementUtils.getSimpleName(rightType)));
+        }
+
+        TypeMirror booleanType = context.getType(boolean.class);
+        boolean valid;
+        if (LOGIC_OPERATORS.contains(operator)) {
+            valid = ElementUtils.typeEquals(leftType, booleanType);
+        } else if (COMPARABLE_OPERATORS.contains(operator)) {
+            valid = ElementUtils.isPrimitive(leftType);
+        } else if (IDENTITY_OPERATORS.contains(operator)) {
+            valid = leftType.getKind().isPrimitive() || leftType.getKind() == TypeKind.DECLARED || leftType.getKind() == TypeKind.ARRAY;
+        } else {
+            throw new InvalidExpressionException(String.format("The operator %s is undefined.", operator));
+        }
+        binary.setResolvedType(booleanType);
+
+        if (!valid) {
+            throw new InvalidExpressionException(String.format("The operator %s is undefined for the argument type(s) %s %s.", operator, ElementUtils.getSimpleName(leftType),
+                            ElementUtils.getSimpleName(rightType)));
+        }
+    }
+
+    public void visitNegate(Negate negate) {
+        TypeMirror booleanType = context.getType(boolean.class);
+        TypeMirror resolvedType = negate.getResolvedType();
+        if (!ElementUtils.typeEquals(resolvedType, booleanType)) {
+            throw new InvalidExpressionException(String.format("The operator %s is undefined for the argument type %s.", "!", ElementUtils.getSimpleName(resolvedType)));
+        }
+    }
+
+    public void visitCall(Call call) {
+        List<ExecutableElement> lookupMethods;
+        DSLExpression receiver = call.getReceiver();
+        if (receiver == null) {
+            lookupMethods = this.methods;
+        } else {
+            TypeMirror type = receiver.getResolvedType();
+            if (type.getKind() == TypeKind.DECLARED) {
+                type = context.reloadType(type); // ensure ECJ has the type loaded
+                lookupMethods = ElementFilter.methodsIn(context.getEnvironment().getElementUtils().getAllMembers((TypeElement) ((DeclaredType) type).asElement()));
+            } else {
+                lookupMethods = Collections.emptyList();
+            }
+        }
+
+        ExecutableElement foundWithName = null;
+        outer: for (ExecutableElement method : lookupMethods) {
+            if (getMethodName(method).equals(call.getName())) {
+                foundWithName = method;
+
+                List<? extends VariableElement> parameters = method.getParameters();
+                if (parameters.size() != call.getParameters().size()) {
+                    continue outer;
+                }
+
+                int parameterIndex = 0;
+                for (DSLExpression expression : call.getParameters()) {
+                    TypeMirror sourceType = expression.getResolvedType();
+                    TypeMirror targetType = parameters.get(parameterIndex).asType();
+                    if (!ElementUtils.isAssignable(sourceType, targetType)) {
+                        continue outer;
+                    }
+                    expression.setResolvedTargetType(targetType);
+                    parameterIndex++;
+                }
+
+                call.setResolvedMethod(method);
+                break;
+            }
+        }
+        if (call.getResolvedMethod() == null) {
+            if (foundWithName == null) {
+                // parameter mismatch
+                throw new InvalidExpressionException(String.format("The method %s is undefined for the enclosing scope.", call.getName()));
+            } else {
+                StringBuilder arguments = new StringBuilder();
+                String sep = "";
+                for (DSLExpression expression : call.getParameters()) {
+                    arguments.append(sep).append(ElementUtils.getSimpleName(expression.getResolvedType()));
+                    sep = ", ";
+                }
+                // name mismatch
+                throw new InvalidExpressionException(String.format("The method %s in the type %s is not applicable for the arguments %s.", //
+                                ElementUtils.getReadableSignature(foundWithName), //
+                                ElementUtils.getSimpleName((TypeElement) foundWithName.getEnclosingElement()), arguments.toString()));
+            }
+        }
+    }
+
+    public void visitVariable(Variable variable) {
+        List<VariableElement> lookupVariables;
+        DSLExpression receiver = variable.getReceiver();
+        if (receiver == null) {
+            lookupVariables = this.variables;
+        } 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"));
+            } else {
+                lookupVariables = Collections.emptyList();
+            }
+        }
+
+        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()));
+        }
+    }
+
+    public void visitIntLiteral(IntLiteral binary) {
+        try {
+            binary.setResolvedType(context.getType(int.class));
+            binary.setResolvedValueInt(Integer.parseInt(binary.getLiteral()));
+        } catch (NumberFormatException e) {
+            throw new InvalidExpressionException(String.format("Type mismatch: cannot convert from String '%s' to int", binary.getLiteral()));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Expression.atg	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+/*
+ * This is the grammar for DSL expressions that is used to automatically generate the Parser.java and Scanner.java
+ * files. You can download the parser generator Coco/R from http://ssw.jku.at/coco/. Then run
+ * "java -jar Coco.jar Expression.atg"
+ */
+
+COMPILER Expression
+
+CHARACTERS
+
+letter = 'A' .. 'Z' + 'a' .. 'z' + '_' + '$'.
+nonZeroDigit = "123456789".
+digit = '0' + nonZeroDigit .
+
+TOKENS
+
+identifier = letter {letter | digit}.
+numericLiteral = "0" | nonZeroDigit { digit }.
+
+PRAGMAS
+
+PRODUCTIONS
+
+
+Expression<out DSLExpression result>
+=
+LogicFactor<out result>
+.
+
+
+LogicFactor<out DSLExpression  result>
+=
+ComparisonFactor<out result>
+[
+    ("||")                                      (. Token op = t; .)
+    ComparisonFactor<out DSLExpression  right>  (.  result = new Binary(op.val, result, right); .)
+]
+.
+
+ComparisonFactor<out DSLExpression  result>
+=
+NegateFactor<out result>
+[
+    ("<" | "<=" | ">" | ">=" | "==" | "!=" )    (. Token op = t; .)
+    NegateFactor<out DSLExpression  right>      (.  result = new Binary(op.val, result, right); .)
+]
+.
+
+
+NegateFactor<out DSLExpression  result>
+=                                               (. boolean negated = false; .)
+[
+    "!"                                         (. negated = true; .)
+]                                        
+    Factor<out result>                          (. result = negated ? new Negate(result) : result;.)
+.
+
+
+Factor<out DSLExpression result>
+=                                               (. result = null; .)
+
+(
+    MemberExpression<out result, result>
+|
+    numericLiteral                              (. result = new IntLiteral(t.val); .)
+|
+    "("                                        
+    Expression<out result>                      
+    ")"                                        
+                                                
+)
+.
+
+MemberExpression<out DSLExpression result, DSLExpression receiver>
+=                                               (. result = null; .)
+(
+    
+    identifier                                  (. Variable variable = new Variable(receiver, t.val); .)
+                                                (. result = variable; .)
+[
+
+    "("                                         (. List<DSLExpression> parameters = new ArrayList<>();
+                                                   DSLExpression parameter; .)
+    [
+        Expression<out parameter>               (. parameters.add(parameter); .)
+        {
+            ","
+            Expression<out parameter>           (. parameters.add(parameter); .)
+        }
+    ]
+    ")"                                         (. result = new Call(variable.getReceiver(), variable.getName(), parameters); .)
+]
+                                                
+)
+[
+   "." MemberExpression<out result, result>
+]
+.
+END Expression.
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/InvalidExpressionException.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,32 @@
+/*
+ * 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.dsl.processor.expression;
+
+public class InvalidExpressionException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public InvalidExpressionException(String message) {
+        super(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Parser.frame	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,211 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported from C# to Java by Wolfgang Ahorner
+with improvements by Pat Terry, Rhodes University
+
+This program is free software; you can redistribute it and/or modify it 
+under the terms of the GNU General Public License as published by the 
+Free Software Foundation; either version 2, or (at your option) any 
+later version.
+
+This program 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 
+for more details.
+
+You should have received a copy of the GNU General Public License along 
+with this program; if not, write to the Free Software Foundation, Inc., 
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than 
+Coco/R itself) does not fall under the GNU General Public License.
+------------------------------------------------------------------------*/
+-->begin
+package com.oracle.truffle.dsl.processor.expression;
+
+import java.util.*;
+import java.io.*;
+import java.nio.charset.*;
+
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.*;
+
+// Checkstyle: stop
+// @formatter:off
+class Parser {
+-->constants
+    static final boolean _T = true;
+    static final boolean _x = false;
+    static final int minErrDist = 2;
+
+    public Token t; // last recognized token
+    public Token la; // lookahead token
+    int errDist = minErrDist;
+
+    public final Scanner scanner;
+    public final Errors errors;
+    
+    -->declarations
+    public Parser(InputStream input) {
+        this.scanner = new Scanner(input);
+        errors = new Errors();
+    }
+
+    void SynErr(int n) {
+        if (errDist >= minErrDist)
+            errors.SynErr(la.line, la.col, n);
+        errDist = 0;
+    }
+
+    public void SemErr(String msg) {
+        if (errDist >= minErrDist)
+            errors.SemErr(t.line, t.col, msg);
+        errDist = 0;
+    }
+
+    void Get() {
+        for (;;) {
+            t = la;
+            la = scanner.Scan();
+            if (la.kind <= maxT) {
+                ++errDist;
+                break;
+            }
+-->pragmas
+            la = t;
+        }
+    }
+
+    void Expect(int n) {
+        if (la.kind == n)
+            Get();
+        else {
+            SynErr(n);
+        }
+    }
+
+    boolean StartOf(int s) {
+        return set[s][la.kind];
+    }
+
+    void ExpectWeak(int n, int follow) {
+        if (la.kind == n)
+            Get();
+        else {
+            SynErr(n);
+            while (!StartOf(follow))
+                Get();
+        }
+    }
+
+    boolean WeakSeparator(int n, int syFol, int repFol) {
+        int kind = la.kind;
+        if (kind == n) {
+            Get();
+            return true;
+        } else if (StartOf(repFol))
+            return false;
+        else {
+            SynErr(n);
+            while (!(set[syFol][kind] || set[repFol][kind] || set[0][kind])) {
+                Get();
+                kind = la.kind;
+            }
+            return StartOf(syFol);
+        }
+    }
+
+-->productions
+
+    private DSLExpression parseImpl() {
+        la = new Token();
+        la.val = "";
+        Get();
+        DSLExpression result = -->parseRoot
+        return result;
+    }
+
+    private static final boolean[][] set = {
+-->initialization
+    };
+
+    public static DSLExpression parse(InputStream input) {
+        Parser parser = new Parser(input);
+        DSLExpression result = parser.parseImpl();
+        if (parser.errors.errors.size() > 0) {
+            StringBuilder msg = new StringBuilder();
+            for (String error : parser.errors.errors) {
+                msg.append(error).append("\n");
+            }
+            throw new InvalidExpressionException(msg.toString());
+        }
+        return result;
+    }
+
+    public static DSLExpression parse(String s) {
+        return parse(new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)));
+    }
+} // end Parser
+
+class Errors {
+
+    protected final List<String> errors = new ArrayList<>();
+    public String errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
+
+    protected void printMsg(int line, int column, String msg) {
+        StringBuffer b = new StringBuffer(errMsgFormat);
+        int pos = b.indexOf("{0}");
+        if (pos >= 0) {
+            b.delete(pos, pos + 3);
+            b.insert(pos, line);
+        }
+        pos = b.indexOf("{1}");
+        if (pos >= 0) {
+            b.delete(pos, pos + 3);
+            b.insert(pos, column);
+        }
+        pos = b.indexOf("{2}");
+        if (pos >= 0)
+            b.replace(pos, pos + 3, msg);
+        errors.add(b.toString());
+    }
+
+    public void SynErr(int line, int col, int n) {
+        String s;
+        switch (n) {-->errors
+            default:
+                s = "error " + n;
+                break;
+        }
+        printMsg(line, col, s);
+    }
+
+    public void SemErr(int line, int col, String s) {
+        printMsg(line, col, s);
+    }
+
+    public void SemErr(String s) {
+        errors.add(s);
+    }
+
+    public void Warning(int line, int col, String s) {
+        printMsg(line, col, s);
+    }
+
+    public void Warning(String s) {
+        errors.add(s);
+    }
+} // Errors
+
+class FatalError extends RuntimeException {
+
+    public static final long serialVersionUID = 1L;
+
+    public FatalError(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Parser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+
+// The content of this file is automatically generated. DO NOT EDIT.
+
+package com.oracle.truffle.dsl.processor.expression;
+
+import java.util.*;
+import java.io.*;
+import java.nio.charset.*;
+
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.*;
+
+// Checkstyle: stop
+// @formatter:off
+class Parser {
+	public static final int _EOF = 0;
+	public static final int _identifier = 1;
+	public static final int _numericLiteral = 2;
+	public static final int maxT = 15;
+
+    static final boolean _T = true;
+    static final boolean _x = false;
+    static final int minErrDist = 2;
+
+    public Token t; // last recognized token
+    public Token la; // lookahead token
+    int errDist = minErrDist;
+
+    public final Scanner scanner;
+    public final Errors errors;
+    
+    
+    public Parser(InputStream input) {
+        this.scanner = new Scanner(input);
+        errors = new Errors();
+    }
+
+    void SynErr(int n) {
+        if (errDist >= minErrDist)
+            errors.SynErr(la.line, la.col, n);
+        errDist = 0;
+    }
+
+    public void SemErr(String msg) {
+        if (errDist >= minErrDist)
+            errors.SemErr(t.line, t.col, msg);
+        errDist = 0;
+    }
+
+    void Get() {
+        for (;;) {
+            t = la;
+            la = scanner.Scan();
+            if (la.kind <= maxT) {
+                ++errDist;
+                break;
+            }
+
+            la = t;
+        }
+    }
+
+    void Expect(int n) {
+        if (la.kind == n)
+            Get();
+        else {
+            SynErr(n);
+        }
+    }
+
+    boolean StartOf(int s) {
+        return set[s][la.kind];
+    }
+
+    void ExpectWeak(int n, int follow) {
+        if (la.kind == n)
+            Get();
+        else {
+            SynErr(n);
+            while (!StartOf(follow))
+                Get();
+        }
+    }
+
+    boolean WeakSeparator(int n, int syFol, int repFol) {
+        int kind = la.kind;
+        if (kind == n) {
+            Get();
+            return true;
+        } else if (StartOf(repFol))
+            return false;
+        else {
+            SynErr(n);
+            while (!(set[syFol][kind] || set[repFol][kind] || set[0][kind])) {
+                Get();
+                kind = la.kind;
+            }
+            return StartOf(syFol);
+        }
+    }
+
+	DSLExpression  Expression() {
+		DSLExpression  result;
+		result = LogicFactor();
+		return result;
+	}
+
+	DSLExpression   LogicFactor() {
+		DSLExpression   result;
+		result = ComparisonFactor();
+		if (la.kind == 3) {
+			Get();
+			Token op = t; 
+			DSLExpression  right = ComparisonFactor();
+			result = new Binary(op.val, result, right); 
+		}
+		return result;
+	}
+
+	DSLExpression   ComparisonFactor() {
+		DSLExpression   result;
+		result = NegateFactor();
+		if (StartOf(1)) {
+			switch (la.kind) {
+			case 4: {
+				Get();
+				break;
+			}
+			case 5: {
+				Get();
+				break;
+			}
+			case 6: {
+				Get();
+				break;
+			}
+			case 7: {
+				Get();
+				break;
+			}
+			case 8: {
+				Get();
+				break;
+			}
+			case 9: {
+				Get();
+				break;
+			}
+			}
+			Token op = t; 
+			DSLExpression  right = NegateFactor();
+			result = new Binary(op.val, result, right); 
+		}
+		return result;
+	}
+
+	DSLExpression   NegateFactor() {
+		DSLExpression   result;
+		boolean negated = false; 
+		if (la.kind == 10) {
+			Get();
+			negated = true; 
+		}
+		result = Factor();
+		result = negated ? new Negate(result) : result;
+		return result;
+	}
+
+	DSLExpression  Factor() {
+		DSLExpression  result;
+		result = null; 
+		if (la.kind == 1) {
+			result = MemberExpression(result);
+		} else if (la.kind == 2) {
+			Get();
+			result = new IntLiteral(t.val); 
+		} else if (la.kind == 11) {
+			Get();
+			result = Expression();
+			Expect(12);
+		} else SynErr(16);
+		return result;
+	}
+
+	DSLExpression  MemberExpression(DSLExpression receiver) {
+		DSLExpression  result;
+		result = null; 
+		Expect(1);
+		Variable variable = new Variable(receiver, t.val); 
+		result = variable; 
+		if (la.kind == 11) {
+			Get();
+			List<DSLExpression> parameters = new ArrayList<>();
+			DSLExpression parameter; 
+			if (StartOf(2)) {
+				parameter = Expression();
+				parameters.add(parameter); 
+				while (la.kind == 13) {
+					Get();
+					parameter = Expression();
+					parameters.add(parameter); 
+				}
+			}
+			Expect(12);
+			result = new Call(variable.getReceiver(), variable.getName(), parameters); 
+		}
+		if (la.kind == 14) {
+			Get();
+			result = MemberExpression(result);
+		}
+		return result;
+	}
+
+
+
+    private DSLExpression parseImpl() {
+        la = new Token();
+        la.val = "";
+        Get();
+        DSLExpression result = 		Expression();
+		Expect(0);
+
+        return result;
+    }
+
+    private static final boolean[][] set = {
+		{_T,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x,_x,_x,_x, _x},
+		{_x,_x,_x,_x, _T,_T,_T,_T, _T,_T,_x,_x, _x,_x,_x,_x, _x},
+		{_x,_T,_T,_x, _x,_x,_x,_x, _x,_x,_T,_T, _x,_x,_x,_x, _x}
+
+    };
+
+    public static DSLExpression parse(InputStream input) {
+        Parser parser = new Parser(input);
+        DSLExpression result = parser.parseImpl();
+        if (parser.errors.errors.size() > 0) {
+            StringBuilder msg = new StringBuilder();
+            for (String error : parser.errors.errors) {
+                msg.append(error).append("\n");
+            }
+            throw new InvalidExpressionException(msg.toString());
+        }
+        return result;
+    }
+
+    public static DSLExpression parse(String s) {
+        return parse(new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8)));
+    }
+} // end Parser
+
+class Errors {
+
+    protected final List<String> errors = new ArrayList<>();
+    public String errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
+
+    protected void printMsg(int line, int column, String msg) {
+        StringBuffer b = new StringBuffer(errMsgFormat);
+        int pos = b.indexOf("{0}");
+        if (pos >= 0) {
+            b.delete(pos, pos + 3);
+            b.insert(pos, line);
+        }
+        pos = b.indexOf("{1}");
+        if (pos >= 0) {
+            b.delete(pos, pos + 3);
+            b.insert(pos, column);
+        }
+        pos = b.indexOf("{2}");
+        if (pos >= 0)
+            b.replace(pos, pos + 3, msg);
+        errors.add(b.toString());
+    }
+
+    public void SynErr(int line, int col, int n) {
+        String s;
+        switch (n) {
+			case 0: s = "EOF expected"; break;
+			case 1: s = "identifier expected"; break;
+			case 2: s = "numericLiteral expected"; break;
+			case 3: s = "\"||\" expected"; break;
+			case 4: s = "\"<\" expected"; break;
+			case 5: s = "\"<=\" expected"; break;
+			case 6: s = "\">\" expected"; break;
+			case 7: s = "\">=\" expected"; break;
+			case 8: s = "\"==\" expected"; break;
+			case 9: s = "\"!=\" expected"; break;
+			case 10: s = "\"!\" expected"; break;
+			case 11: s = "\"(\" expected"; break;
+			case 12: s = "\")\" expected"; break;
+			case 13: s = "\",\" expected"; break;
+			case 14: s = "\".\" expected"; break;
+			case 15: s = "??? expected"; break;
+			case 16: s = "invalid Factor"; break;
+            default:
+                s = "error " + n;
+                break;
+        }
+        printMsg(line, col, s);
+    }
+
+    public void SemErr(int line, int col, String s) {
+        printMsg(line, col, s);
+    }
+
+    public void SemErr(String s) {
+        errors.add(s);
+    }
+
+    public void Warning(int line, int col, String s) {
+        printMsg(line, col, s);
+    }
+
+    public void Warning(String s) {
+        errors.add(s);
+    }
+} // Errors
+
+class FatalError extends RuntimeException {
+
+    public static final long serialVersionUID = 1L;
+
+    public FatalError(String s) {
+        super(s);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Scanner.frame	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,495 @@
+/*-------------------------------------------------------------------------
+Compiler Generator Coco/R,
+Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
+extended by M. Loeberbauer & A. Woess, Univ. of Linz
+ported from C# to Java by Wolfgang Ahorner
+with improvements by Pat Terry, Rhodes University
+
+This program is free software; you can redistribute it and/or modify it 
+under the terms of the GNU General Public License as published by the 
+Free Software Foundation; either version 2, or (at your option) any 
+later version.
+
+This program 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 
+for more details.
+
+You should have received a copy of the GNU General Public License along 
+with this program; if not, write to the Free Software Foundation, Inc., 
+59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+As an exception, it is allowed to write an extension of Coco/R that is
+used as a plugin in non-free software.
+
+If not otherwise stated, any source code generated by Coco/R (other than 
+Coco/R itself) does not fall under the GNU General Public License.
+------------------------------------------------------------------------*/
+-->begin
+package com.oracle.truffle.dsl.processor.expression;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Map;
+import java.util.HashMap;
+
+// Checkstyle: stop
+// @formatter:off
+class Token {
+
+    public int kind; // token kind
+    public int pos; // token position in bytes in the source text (starting at 0)
+    public int charPos; // token position in characters in the source text (starting at 0)
+    public int col; // token column (starting at 1)
+    public int line; // token line (starting at 1)
+    public String val; // token value
+    public Token next; // ML 2005-03-11 Peek tokens are kept in linked list
+}
+
+// -----------------------------------------------------------------------------------
+// Buffer
+// -----------------------------------------------------------------------------------
+class Buffer {
+
+    // This Buffer supports the following cases:
+    // 1) seekable stream (file)
+    // a) whole stream in buffer
+    // b) part of stream in buffer
+    // 2) non seekable stream (network, console)
+
+    public static final int EOF = Character.MAX_VALUE + 1;
+    private static final int MIN_BUFFER_LENGTH = 1024; // 1KB
+    private static final int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB
+    private byte[] buf; // input buffer
+    private int bufStart; // position of first byte in buffer relative to input stream
+    private int bufLen; // length of buffer
+    private int fileLen; // length of input stream (may change if stream is no file)
+    private int bufPos; // current position in buffer
+    private RandomAccessFile file; // input stream (seekable)
+    private InputStream stream; // growing input stream (e.g.: console, network)
+
+    public Buffer(InputStream s) {
+        stream = s;
+        fileLen = bufLen = bufStart = bufPos = 0;
+        buf = new byte[MIN_BUFFER_LENGTH];
+    }
+
+    public Buffer(String fileName) {
+        try {
+            file = new RandomAccessFile(fileName, "r");
+            fileLen = (int) file.length();
+            bufLen = Math.min(fileLen, MAX_BUFFER_LENGTH);
+            buf = new byte[bufLen];
+            bufStart = Integer.MAX_VALUE; // nothing in buffer so far
+            if (fileLen > 0)
+                setPos(0); // setup buffer to position 0 (start)
+            else
+                bufPos = 0; // index 0 is already after the file, thus setPos(0) is invalid
+            if (bufLen == fileLen)
+                Close();
+        } catch (IOException e) {
+            throw new FatalError("Could not open file " + fileName);
+        }
+    }
+
+    // don't use b after this call anymore
+    // called in UTF8Buffer constructor
+    protected Buffer(Buffer b) {
+        buf = b.buf;
+        bufStart = b.bufStart;
+        bufLen = b.bufLen;
+        fileLen = b.fileLen;
+        bufPos = b.bufPos;
+        file = b.file;
+        stream = b.stream;
+        // keep finalize from closing the file
+        b.file = null;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        super.finalize();
+        Close();
+    }
+
+    protected void Close() {
+        if (file != null) {
+            try {
+                file.close();
+                file = null;
+            } catch (IOException e) {
+                throw new FatalError(e.getMessage());
+            }
+        }
+    }
+
+    public int Read() {
+        if (bufPos < bufLen) {
+            return buf[bufPos++] & 0xff; // mask out sign bits
+        } else if (getPos() < fileLen) {
+            setPos(getPos()); // shift buffer start to pos
+            return buf[bufPos++] & 0xff; // mask out sign bits
+        } else if (stream != null && ReadNextStreamChunk() > 0) {
+            return buf[bufPos++] & 0xff; // mask out sign bits
+        } else {
+            return EOF;
+        }
+    }
+
+    public int Peek() {
+        int curPos = getPos();
+        int ch = Read();
+        setPos(curPos);
+        return ch;
+    }
+
+    // beg .. begin, zero-based, inclusive, in byte
+    // end .. end, zero-based, exclusive, in byte
+    public String GetString(int beg, int end) {
+        int len = 0;
+        char[] buffer = new char[end - beg];
+        int oldPos = getPos();
+        setPos(beg);
+        while (getPos() < end)
+            buffer[len++] = (char) Read();
+        setPos(oldPos);
+        return new String(buffer, 0, len);
+    }
+
+    public int getPos() {
+        return bufPos + bufStart;
+    }
+
+    public void setPos(int value) {
+        if (value >= fileLen && stream != null) {
+            // Wanted position is after buffer and the stream
+            // is not seek-able e.g. network or console,
+            // thus we have to read the stream manually till
+            // the wanted position is in sight.
+            while (value >= fileLen && ReadNextStreamChunk() > 0) {
+                // nothing to do...
+            }
+        }
+
+        if (value < 0 || value > fileLen) {
+            throw new FatalError("buffer out of bounds access, position: " + value);
+        }
+
+        if (value >= bufStart && value < bufStart + bufLen) { // already in buffer
+            bufPos = value - bufStart;
+        } else if (file != null) { // must be swapped in
+            try {
+                file.seek(value);
+                bufLen = file.read(buf);
+                bufStart = value;
+                bufPos = 0;
+            } catch (IOException e) {
+                throw new FatalError(e.getMessage());
+            }
+        } else {
+            // set the position to the end of the file, Pos will return fileLen.
+            bufPos = fileLen - bufStart;
+        }
+    }
+
+    // Read the next chunk of bytes from the stream, increases the buffer
+    // if needed and updates the fields fileLen and bufLen.
+    // Returns the number of bytes read.
+    private int ReadNextStreamChunk() {
+        int free = buf.length - bufLen;
+        if (free == 0) {
+            // in the case of a growing input stream
+            // we can neither seek in the stream, nor can we
+            // foresee the maximum length, thus we must adapt
+            // the buffer size on demand.
+            byte[] newBuf = new byte[bufLen * 2];
+            System.arraycopy(buf, 0, newBuf, 0, bufLen);
+            buf = newBuf;
+            free = bufLen;
+        }
+
+        int read;
+        try {
+            read = stream.read(buf, bufLen, free);
+        } catch (IOException ioex) {
+            throw new FatalError(ioex.getMessage());
+        }
+
+        if (read > 0) {
+            fileLen = bufLen = (bufLen + read);
+            return read;
+        }
+        // end of stream reached
+        return 0;
+    }
+}
+
+// -----------------------------------------------------------------------------------
+// UTF8Buffer
+// -----------------------------------------------------------------------------------
+class UTF8Buffer extends Buffer {
+
+    UTF8Buffer(Buffer b) {
+        super(b);
+    }
+
+    @Override
+    public int Read() {
+        int ch;
+        do {
+            ch = super.Read();
+            // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+        } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));
+        if (ch < 128 || ch == EOF) {
+            // nothing to do, first 127 chars are the same in ascii and utf8
+            // 0xxxxxxx or end of file character
+        } else if ((ch & 0xF0) == 0xF0) {
+            // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+            int c1 = ch & 0x07;
+            ch = super.Read();
+            int c2 = ch & 0x3F;
+            ch = super.Read();
+            int c3 = ch & 0x3F;
+            ch = super.Read();
+            int c4 = ch & 0x3F;
+            ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+        } else if ((ch & 0xE0) == 0xE0) {
+            // 1110xxxx 10xxxxxx 10xxxxxx
+            int c1 = ch & 0x0F;
+            ch = super.Read();
+            int c2 = ch & 0x3F;
+            ch = super.Read();
+            int c3 = ch & 0x3F;
+            ch = (((c1 << 6) | c2) << 6) | c3;
+        } else if ((ch & 0xC0) == 0xC0) {
+            // 110xxxxx 10xxxxxx
+            int c1 = ch & 0x1F;
+            ch = super.Read();
+            int c2 = ch & 0x3F;
+            ch = (c1 << 6) | c2;
+        }
+        return ch;
+    }
+}
+
+// -----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+// -----------------------------------------------------------------------------------
+class StartStates {
+
+    private static class Elem {
+
+        public int key, val;
+        public Elem next;
+
+        public Elem(int key, int val) {
+            this.key = key;
+            this.val = val;
+        }
+    }
+
+    private Elem[] tab = new Elem[128];
+
+    public void set(int key, int val) {
+        Elem e = new Elem(key, val);
+        int k = key % 128;
+        e.next = tab[k];
+        tab[k] = e;
+    }
+
+    public int state(int key) {
+        Elem e = tab[key % 128];
+        while (e != null && e.key != key)
+            e = e.next;
+        return e == null ? 0 : e.val;
+    }
+}
+
+// -----------------------------------------------------------------------------------
+// Scanner
+// -----------------------------------------------------------------------------------
+@SuppressWarnings({"rawtypes"})
+public class Scanner {
+
+    static final char EOL = '\n';
+    static final int eofSym = 0;
+-->declarations
+
+    public Buffer buffer; // scanner buffer
+
+    Token t; // current token
+    int ch; // current input character
+    int pos; // byte position of current character
+    int charPos; // position by unicode characters starting with 0
+    int col; // column number of current character
+    int line; // line number of current character
+    int oldEols; // EOLs that appeared in a comment;
+    static final StartStates start; // maps initial token character to start state
+    static final Map literals; // maps literal strings to literal kinds
+
+    Token tokens; // list of tokens already peeked (first token is a dummy)
+    Token pt; // current peek token
+
+    char[] tval = new char[16]; // token text used in NextToken(), dynamically enlarged
+    int tlen; // length of current token
+
+    static {
+        start = new StartStates();
+        literals = new HashMap();
+-->initialization
+    }
+
+    public Scanner(String fileName) {
+        buffer = new Buffer(fileName);
+        Init();
+    }
+
+    public Scanner(InputStream s) {
+        buffer = new Buffer(s);
+        Init();
+    }
+
+    void Init() {
+        pos = -1;
+        line = 1;
+        col = 0;
+        charPos = -1;
+        oldEols = 0;
+        NextCh();
+        if (ch == 0xEF) { // check optional byte order mark for UTF-8
+            NextCh();
+            int ch1 = ch;
+            NextCh();
+            int ch2 = ch;
+            if (ch1 != 0xBB || ch2 != 0xBF) {
+                throw new FatalError("Illegal byte order mark at start of file");
+            }
+            buffer = new UTF8Buffer(buffer);
+            col = 0;
+            charPos = -1;
+            NextCh();
+        }
+        pt = tokens = new Token(); // first token is a dummy
+    }
+
+    void NextCh() {
+        if (oldEols > 0) {
+            ch = EOL;
+            oldEols--;
+        } else {
+            pos = buffer.getPos();
+            // buffer reads unicode chars, if UTF8 has been detected
+            ch = buffer.Read();
+            col++;
+            charPos++;
+            // replace isolated '\r' by '\n' in order to make
+            // eol handling uniform across Windows, Unix and Mac
+            if (ch == '\r' && buffer.Peek() != '\n')
+                ch = EOL;
+            if (ch == EOL) {
+                line++;
+                col = 0;
+            }
+        }
+-->casing
+    }
+
+    void AddCh() {
+        if (tlen >= tval.length) {
+            char[] newBuf = new char[2 * tval.length];
+            System.arraycopy(tval, 0, newBuf, 0, tval.length);
+            tval = newBuf;
+        }
+        if (ch != Buffer.EOF) {
+-->casing2
+            NextCh();
+        }
+    }
+
+-->comments
+
+    void CheckLiteral() {
+        String val = t.val;
+-->casing3
+        Object kind = literals.get(val);
+        if (kind != null) {
+            t.kind = ((Integer) kind).intValue();
+        }
+    }
+
+    Token NextToken() {
+        while (ch == ' ' || 
+-->scan1
+        ) NextCh();
+-->scan2
+        int recKind = noSym;
+        int recEnd = pos;
+        t = new Token();
+        t.pos = pos;
+        t.col = col;
+        t.line = line;
+        t.charPos = charPos;
+        int state = start.state(ch);
+        tlen = 0;
+        AddCh();
+
+        loop: for (;;) {
+            switch (state) {
+                case -1: {
+                    t.kind = eofSym;
+                    break loop;
+                } // NextCh already done
+                case 0: {
+                    if (recKind != noSym) {
+                        tlen = recEnd - t.pos;
+                        SetScannerBehindT();
+                    }
+                    t.kind = recKind;
+                    break loop;
+                } // NextCh already done
+-->scan3
+            }
+        }
+        t.val = new String(tval, 0, tlen);
+        return t;
+    }
+
+    private void SetScannerBehindT() {
+        buffer.setPos(t.pos);
+        NextCh();
+        line = t.line;
+        col = t.col;
+        charPos = t.charPos;
+        for (int i = 0; i < tlen; i++)
+            NextCh();
+    }
+
+    // get the next token (possibly a token already seen during peeking)
+    public Token Scan() {
+        if (tokens.next == null) {
+            return NextToken();
+        } else {
+            pt = tokens = tokens.next;
+            return tokens;
+        }
+    }
+
+    // get the next token, ignore pragmas
+    public Token Peek() {
+        do {
+            if (pt.next == null) {
+                pt.next = NextToken();
+            }
+            pt = pt.next;
+        } while (pt.kind > maxT); // skip pragmas
+
+        return pt;
+    }
+
+    // make sure that peeking starts at current scan position
+    public void ResetPeek() {
+        pt = tokens;
+    }
+
+} // end Scanner
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/expression/Scanner.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,557 @@
+/*
+ * 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.
+ */
+
+// The content of this file is automatically generated. DO NOT EDIT.
+
+package com.oracle.truffle.dsl.processor.expression;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Map;
+import java.util.HashMap;
+
+// Checkstyle: stop
+// @formatter:off
+class Token {
+
+    public int kind; // token kind
+    public int pos; // token position in bytes in the source text (starting at 0)
+    public int charPos; // token position in characters in the source text (starting at 0)
+    public int col; // token column (starting at 1)
+    public int line; // token line (starting at 1)
+    public String val; // token value
+    public Token next; // ML 2005-03-11 Peek tokens are kept in linked list
+}
+
+// -----------------------------------------------------------------------------------
+// Buffer
+// -----------------------------------------------------------------------------------
+class Buffer {
+
+    // This Buffer supports the following cases:
+    // 1) seekable stream (file)
+    // a) whole stream in buffer
+    // b) part of stream in buffer
+    // 2) non seekable stream (network, console)
+
+    public static final int EOF = Character.MAX_VALUE + 1;
+    private static final int MIN_BUFFER_LENGTH = 1024; // 1KB
+    private static final int MAX_BUFFER_LENGTH = MIN_BUFFER_LENGTH * 64; // 64KB
+    private byte[] buf; // input buffer
+    private int bufStart; // position of first byte in buffer relative to input stream
+    private int bufLen; // length of buffer
+    private int fileLen; // length of input stream (may change if stream is no file)
+    private int bufPos; // current position in buffer
+    private RandomAccessFile file; // input stream (seekable)
+    private InputStream stream; // growing input stream (e.g.: console, network)
+
+    public Buffer(InputStream s) {
+        stream = s;
+        fileLen = bufLen = bufStart = bufPos = 0;
+        buf = new byte[MIN_BUFFER_LENGTH];
+    }
+
+    public Buffer(String fileName) {
+        try {
+            file = new RandomAccessFile(fileName, "r");
+            fileLen = (int) file.length();
+            bufLen = Math.min(fileLen, MAX_BUFFER_LENGTH);
+            buf = new byte[bufLen];
+            bufStart = Integer.MAX_VALUE; // nothing in buffer so far
+            if (fileLen > 0)
+                setPos(0); // setup buffer to position 0 (start)
+            else
+                bufPos = 0; // index 0 is already after the file, thus setPos(0) is invalid
+            if (bufLen == fileLen)
+                Close();
+        } catch (IOException e) {
+            throw new FatalError("Could not open file " + fileName);
+        }
+    }
+
+    // don't use b after this call anymore
+    // called in UTF8Buffer constructor
+    protected Buffer(Buffer b) {
+        buf = b.buf;
+        bufStart = b.bufStart;
+        bufLen = b.bufLen;
+        fileLen = b.fileLen;
+        bufPos = b.bufPos;
+        file = b.file;
+        stream = b.stream;
+        // keep finalize from closing the file
+        b.file = null;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        super.finalize();
+        Close();
+    }
+
+    protected void Close() {
+        if (file != null) {
+            try {
+                file.close();
+                file = null;
+            } catch (IOException e) {
+                throw new FatalError(e.getMessage());
+            }
+        }
+    }
+
+    public int Read() {
+        if (bufPos < bufLen) {
+            return buf[bufPos++] & 0xff; // mask out sign bits
+        } else if (getPos() < fileLen) {
+            setPos(getPos()); // shift buffer start to pos
+            return buf[bufPos++] & 0xff; // mask out sign bits
+        } else if (stream != null && ReadNextStreamChunk() > 0) {
+            return buf[bufPos++] & 0xff; // mask out sign bits
+        } else {
+            return EOF;
+        }
+    }
+
+    public int Peek() {
+        int curPos = getPos();
+        int ch = Read();
+        setPos(curPos);
+        return ch;
+    }
+
+    // beg .. begin, zero-based, inclusive, in byte
+    // end .. end, zero-based, exclusive, in byte
+    public String GetString(int beg, int end) {
+        int len = 0;
+        char[] buffer = new char[end - beg];
+        int oldPos = getPos();
+        setPos(beg);
+        while (getPos() < end)
+            buffer[len++] = (char) Read();
+        setPos(oldPos);
+        return new String(buffer, 0, len);
+    }
+
+    public int getPos() {
+        return bufPos + bufStart;
+    }
+
+    public void setPos(int value) {
+        if (value >= fileLen && stream != null) {
+            // Wanted position is after buffer and the stream
+            // is not seek-able e.g. network or console,
+            // thus we have to read the stream manually till
+            // the wanted position is in sight.
+            while (value >= fileLen && ReadNextStreamChunk() > 0) {
+                // nothing to do...
+            }
+        }
+
+        if (value < 0 || value > fileLen) {
+            throw new FatalError("buffer out of bounds access, position: " + value);
+        }
+
+        if (value >= bufStart && value < bufStart + bufLen) { // already in buffer
+            bufPos = value - bufStart;
+        } else if (file != null) { // must be swapped in
+            try {
+                file.seek(value);
+                bufLen = file.read(buf);
+                bufStart = value;
+                bufPos = 0;
+            } catch (IOException e) {
+                throw new FatalError(e.getMessage());
+            }
+        } else {
+            // set the position to the end of the file, Pos will return fileLen.
+            bufPos = fileLen - bufStart;
+        }
+    }
+
+    // Read the next chunk of bytes from the stream, increases the buffer
+    // if needed and updates the fields fileLen and bufLen.
+    // Returns the number of bytes read.
+    private int ReadNextStreamChunk() {
+        int free = buf.length - bufLen;
+        if (free == 0) {
+            // in the case of a growing input stream
+            // we can neither seek in the stream, nor can we
+            // foresee the maximum length, thus we must adapt
+            // the buffer size on demand.
+            byte[] newBuf = new byte[bufLen * 2];
+            System.arraycopy(buf, 0, newBuf, 0, bufLen);
+            buf = newBuf;
+            free = bufLen;
+        }
+
+        int read;
+        try {
+            read = stream.read(buf, bufLen, free);
+        } catch (IOException ioex) {
+            throw new FatalError(ioex.getMessage());
+        }
+
+        if (read > 0) {
+            fileLen = bufLen = (bufLen + read);
+            return read;
+        }
+        // end of stream reached
+        return 0;
+    }
+}
+
+// -----------------------------------------------------------------------------------
+// UTF8Buffer
+// -----------------------------------------------------------------------------------
+class UTF8Buffer extends Buffer {
+
+    UTF8Buffer(Buffer b) {
+        super(b);
+    }
+
+    @Override
+    public int Read() {
+        int ch;
+        do {
+            ch = super.Read();
+            // until we find a utf8 start (0xxxxxxx or 11xxxxxx)
+        } while ((ch >= 128) && ((ch & 0xC0) != 0xC0) && (ch != EOF));
+        if (ch < 128 || ch == EOF) {
+            // nothing to do, first 127 chars are the same in ascii and utf8
+            // 0xxxxxxx or end of file character
+        } else if ((ch & 0xF0) == 0xF0) {
+            // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+            int c1 = ch & 0x07;
+            ch = super.Read();
+            int c2 = ch & 0x3F;
+            ch = super.Read();
+            int c3 = ch & 0x3F;
+            ch = super.Read();
+            int c4 = ch & 0x3F;
+            ch = (((((c1 << 6) | c2) << 6) | c3) << 6) | c4;
+        } else if ((ch & 0xE0) == 0xE0) {
+            // 1110xxxx 10xxxxxx 10xxxxxx
+            int c1 = ch & 0x0F;
+            ch = super.Read();
+            int c2 = ch & 0x3F;
+            ch = super.Read();
+            int c3 = ch & 0x3F;
+            ch = (((c1 << 6) | c2) << 6) | c3;
+        } else if ((ch & 0xC0) == 0xC0) {
+            // 110xxxxx 10xxxxxx
+            int c1 = ch & 0x1F;
+            ch = super.Read();
+            int c2 = ch & 0x3F;
+            ch = (c1 << 6) | c2;
+        }
+        return ch;
+    }
+}
+
+// -----------------------------------------------------------------------------------
+// StartStates -- maps characters to start states of tokens
+// -----------------------------------------------------------------------------------
+class StartStates {
+
+    private static class Elem {
+
+        public int key, val;
+        public Elem next;
+
+        public Elem(int key, int val) {
+            this.key = key;
+            this.val = val;
+        }
+    }
+
+    private Elem[] tab = new Elem[128];
+
+    public void set(int key, int val) {
+        Elem e = new Elem(key, val);
+        int k = key % 128;
+        e.next = tab[k];
+        tab[k] = e;
+    }
+
+    public int state(int key) {
+        Elem e = tab[key % 128];
+        while (e != null && e.key != key)
+            e = e.next;
+        return e == null ? 0 : e.val;
+    }
+}
+
+// -----------------------------------------------------------------------------------
+// Scanner
+// -----------------------------------------------------------------------------------
+@SuppressWarnings({"rawtypes"})
+public class Scanner {
+
+    static final char EOL = '\n';
+    static final int eofSym = 0;
+	static final int maxT = 15;
+	static final int noSym = 15;
+
+
+    public Buffer buffer; // scanner buffer
+
+    Token t; // current token
+    int ch; // current input character
+    int pos; // byte position of current character
+    int charPos; // position by unicode characters starting with 0
+    int col; // column number of current character
+    int line; // line number of current character
+    int oldEols; // EOLs that appeared in a comment;
+    static final StartStates start; // maps initial token character to start state
+    static final Map literals; // maps literal strings to literal kinds
+
+    Token tokens; // list of tokens already peeked (first token is a dummy)
+    Token pt; // current peek token
+
+    char[] tval = new char[16]; // token text used in NextToken(), dynamically enlarged
+    int tlen; // length of current token
+
+    static {
+        start = new StartStates();
+        literals = new HashMap();
+		for (int i = 36; i <= 36; ++i) start.set(i, 1);
+		for (int i = 65; i <= 90; ++i) start.set(i, 1);
+		for (int i = 95; i <= 95; ++i) start.set(i, 1);
+		for (int i = 97; i <= 122; ++i) start.set(i, 1);
+		for (int i = 49; i <= 57; ++i) start.set(i, 2);
+		start.set(48, 3); 
+		start.set(124, 4); 
+		start.set(60, 15); 
+		start.set(62, 16); 
+		start.set(61, 8); 
+		start.set(33, 17); 
+		start.set(40, 11); 
+		start.set(41, 12); 
+		start.set(44, 13); 
+		start.set(46, 14); 
+		start.set(Buffer.EOF, -1);
+
+    }
+
+    public Scanner(String fileName) {
+        buffer = new Buffer(fileName);
+        Init();
+    }
+
+    public Scanner(InputStream s) {
+        buffer = new Buffer(s);
+        Init();
+    }
+
+    void Init() {
+        pos = -1;
+        line = 1;
+        col = 0;
+        charPos = -1;
+        oldEols = 0;
+        NextCh();
+        if (ch == 0xEF) { // check optional byte order mark for UTF-8
+            NextCh();
+            int ch1 = ch;
+            NextCh();
+            int ch2 = ch;
+            if (ch1 != 0xBB || ch2 != 0xBF) {
+                throw new FatalError("Illegal byte order mark at start of file");
+            }
+            buffer = new UTF8Buffer(buffer);
+            col = 0;
+            charPos = -1;
+            NextCh();
+        }
+        pt = tokens = new Token(); // first token is a dummy
+    }
+
+    void NextCh() {
+        if (oldEols > 0) {
+            ch = EOL;
+            oldEols--;
+        } else {
+            pos = buffer.getPos();
+            // buffer reads unicode chars, if UTF8 has been detected
+            ch = buffer.Read();
+            col++;
+            charPos++;
+            // replace isolated '\r' by '\n' in order to make
+            // eol handling uniform across Windows, Unix and Mac
+            if (ch == '\r' && buffer.Peek() != '\n')
+                ch = EOL;
+            if (ch == EOL) {
+                line++;
+                col = 0;
+            }
+        }
+
+    }
+
+    void AddCh() {
+        if (tlen >= tval.length) {
+            char[] newBuf = new char[2 * tval.length];
+            System.arraycopy(tval, 0, newBuf, 0, tval.length);
+            tval = newBuf;
+        }
+        if (ch != Buffer.EOF) {
+			tval[tlen++] = (char)ch; 
+
+            NextCh();
+        }
+    }
+
+
+
+    void CheckLiteral() {
+        String val = t.val;
+
+        Object kind = literals.get(val);
+        if (kind != null) {
+            t.kind = ((Integer) kind).intValue();
+        }
+    }
+
+    Token NextToken() {
+        while (ch == ' ' || 
+			false
+        ) NextCh();
+
+        int recKind = noSym;
+        int recEnd = pos;
+        t = new Token();
+        t.pos = pos;
+        t.col = col;
+        t.line = line;
+        t.charPos = charPos;
+        int state = start.state(ch);
+        tlen = 0;
+        AddCh();
+
+        loop: for (;;) {
+            switch (state) {
+                case -1: {
+                    t.kind = eofSym;
+                    break loop;
+                } // NextCh already done
+                case 0: {
+                    if (recKind != noSym) {
+                        tlen = recEnd - t.pos;
+                        SetScannerBehindT();
+                    }
+                    t.kind = recKind;
+                    break loop;
+                } // NextCh already done
+				case 1:
+					recEnd = pos; recKind = 1;
+					if (ch == '$' || ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z' || ch == '_' || ch >= 'a' && ch <= 'z') {AddCh(); state = 1; break;}
+					else {t.kind = 1; break loop;}
+				case 2:
+					recEnd = pos; recKind = 2;
+					if (ch >= '0' && ch <= '9') {AddCh(); state = 2; break;}
+					else {t.kind = 2; break loop;}
+				case 3:
+					{t.kind = 2; break loop;}
+				case 4:
+					if (ch == '|') {AddCh(); state = 5; break;}
+					else {state = 0; break;}
+				case 5:
+					{t.kind = 3; break loop;}
+				case 6:
+					{t.kind = 5; break loop;}
+				case 7:
+					{t.kind = 7; break loop;}
+				case 8:
+					if (ch == '=') {AddCh(); state = 9; break;}
+					else {state = 0; break;}
+				case 9:
+					{t.kind = 8; break loop;}
+				case 10:
+					{t.kind = 9; break loop;}
+				case 11:
+					{t.kind = 11; break loop;}
+				case 12:
+					{t.kind = 12; break loop;}
+				case 13:
+					{t.kind = 13; break loop;}
+				case 14:
+					{t.kind = 14; break loop;}
+				case 15:
+					recEnd = pos; recKind = 4;
+					if (ch == '=') {AddCh(); state = 6; break;}
+					else {t.kind = 4; break loop;}
+				case 16:
+					recEnd = pos; recKind = 6;
+					if (ch == '=') {AddCh(); state = 7; break;}
+					else {t.kind = 6; break loop;}
+				case 17:
+					recEnd = pos; recKind = 10;
+					if (ch == '=') {AddCh(); state = 10; break;}
+					else {t.kind = 10; break loop;}
+
+            }
+        }
+        t.val = new String(tval, 0, tlen);
+        return t;
+    }
+
+    private void SetScannerBehindT() {
+        buffer.setPos(t.pos);
+        NextCh();
+        line = t.line;
+        col = t.col;
+        charPos = t.charPos;
+        for (int i = 0; i < tlen; i++)
+            NextCh();
+    }
+
+    // get the next token (possibly a token already seen during peeking)
+    public Token Scan() {
+        if (tokens.next == null) {
+            return NextToken();
+        } else {
+            pt = tokens = tokens.next;
+            return tokens;
+        }
+    }
+
+    // get the next token, ignore pragmas
+    public Token Peek() {
+        do {
+            if (pt.next == null) {
+                pt.next = NextToken();
+            }
+            pt = pt.next;
+        } while (pt.kind > maxT); // skip pragmas
+
+        return pt;
+    }
+
+    // make sure that peeking starts at current scan position
+    public void ResetPeek() {
+        pt = tokens;
+    }
+
+} // end Scanner
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/DSLExpressionGenerator.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,158 @@
+/*
+ * 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.dsl.processor.generator;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+
+import com.oracle.truffle.dsl.processor.expression.*;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Binary;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Call;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.DSLExpressionVisitor;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.IntLiteral;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Negate;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Variable;
+import com.oracle.truffle.dsl.processor.java.model.*;
+
+public class DSLExpressionGenerator implements DSLExpressionVisitor {
+
+    private final Map<Variable, CodeTree> bindings;
+    private final CodeTree root;
+    private final Deque<CodeTree> stack = new ArrayDeque<>();
+
+    public DSLExpressionGenerator(CodeTree root, Map<Variable, CodeTree> bindings) {
+        this.bindings = bindings;
+        this.root = root;
+    }
+
+    public void visitBinary(Binary binary) {
+        CodeTree right = stack.pop();
+        CodeTree left = stack.pop();
+        stack.push(combine(left, string(" " + binary.getOperator() + " "), right));
+    }
+
+    public void visitCall(Call call) {
+        ExecutableElement method = call.getResolvedMethod();
+        CodeTree[] parameters = new CodeTree[method.getParameters().size()];
+        for (int i = 0; i < parameters.length; i++) {
+            parameters[parameters.length - i - 1] = pop();
+        }
+
+        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+
+        if (call.getResolvedMethod().getKind() == ElementKind.CONSTRUCTOR) {
+            builder.startNew(call.getResolvedType());
+        } else if (call.getReceiver() == null) {
+            if (isStatic(method)) {
+                builder.startStaticCall(method);
+            } else {
+                if (root != null) {
+                    builder.tree(root).string(".");
+                }
+                builder.startCall(method.getSimpleName().toString());
+            }
+        } else {
+            if (isStatic(method)) {
+                throw new AssertionError("Static calls must not have receivers.");
+            }
+            builder.startCall(pop(), method.getSimpleName().toString());
+        }
+        for (CodeTree parameter : parameters) {
+            builder.tree(parameter);
+        }
+        builder.end();
+
+        push(builder.build());
+    }
+
+    public void visitIntLiteral(IntLiteral binary) {
+        push(string(binary.getLiteral()));
+    }
+
+    public void visitNegate(Negate negate) {
+        push(combine(string("!"), combine(string("("), pop(), string(")"))));
+    }
+
+    public void visitVariable(Variable variable) {
+        VariableElement resolvedVariable = variable.getResolvedVariable();
+        CodeTree tree;
+        if (variable.getReceiver() == null) {
+
+            if (isStatic(resolvedVariable)) {
+                tree = staticReference(resolvedVariable);
+            } else {
+                tree = bindings.get(variable);
+                boolean bound = true;
+                if (tree == null) {
+                    tree = string(resolvedVariable.getSimpleName().toString());
+                    bound = false;
+                }
+                if (root != null && !bound) {
+                    tree = combine(root, string("."), tree);
+                }
+            }
+        } else {
+            if (isStatic(resolvedVariable)) {
+                throw new AssertionError("Static variables cannot have receivers.");
+            }
+            tree = combine(pop(), string("."), string(resolvedVariable.getSimpleName().toString()));
+        }
+        push(tree);
+    }
+
+    private static boolean isStatic(Element element) {
+        return element.getModifiers().contains(Modifier.STATIC);
+    }
+
+    private static CodeTree combine(CodeTree tree1, CodeTree tree2) {
+        return new CodeTreeBuilder(null).startGroup().tree(tree1).tree(tree2).end().build();
+    }
+
+    private static CodeTree combine(CodeTree tree1, CodeTree tree2, CodeTree tree3) {
+        return new CodeTreeBuilder(null).startGroup().tree(tree1).tree(tree2).tree(tree3).end().build();
+    }
+
+    private static CodeTree string(String s) {
+        return CodeTreeBuilder.singleString(s);
+    }
+
+    private static CodeTree staticReference(VariableElement var) {
+        return CodeTreeBuilder.createBuilder().staticReference(var.getEnclosingElement().asType(), var.getSimpleName().toString()).build();
+    }
+
+    private void push(CodeTree tree) {
+        stack.push(tree);
+    }
+
+    private CodeTree pop() {
+        return stack.pop();
+    }
+
+    public static CodeTree write(DSLExpression expression, CodeTree root, Map<Variable, CodeTree> bindings) {
+        DSLExpressionGenerator writer = new DSLExpressionGenerator(root, bindings);
+        expression.accept(writer);
+        return combine(string("("), writer.pop(), string(")"));
+    }
+
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java	Thu Feb 12 04:01:46 2015 +0100
@@ -35,6 +35,7 @@
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.dsl.internal.DSLOptions.*;
 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.*;
 
@@ -148,4 +149,46 @@
         return clazz;
     }
 
+    public static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
+        List<ExecutableElement> constructors = new ArrayList<>();
+        for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(nodeType).getEnclosedElements())) {
+            if (constructor.getModifiers().contains(PRIVATE)) {
+                continue;
+            }
+            if (isCopyConstructor(constructor)) {
+                continue;
+            }
+            constructors.add(constructor);
+        }
+
+        if (constructors.isEmpty()) {
+            constructors.add(new CodeExecutableElement(null, ElementUtils.getSimpleName(nodeType)));
+        }
+
+        return constructors;
+    }
+
+    public static boolean isCopyConstructor(ExecutableElement element) {
+        if (element.getParameters().size() != 1) {
+            return false;
+        }
+        VariableElement var = element.getParameters().get(0);
+        TypeElement enclosingType = ElementUtils.findNearestEnclosingType(var);
+        if (ElementUtils.typeEquals(var.asType(), enclosingType.asType())) {
+            return true;
+        }
+        List<TypeElement> types = ElementUtils.getDirectSuperTypes(enclosingType);
+        for (TypeElement type : types) {
+            if (!(type instanceof CodeTypeElement)) {
+                // no copy constructors which are not generated types
+                return false;
+            }
+
+            if (ElementUtils.typeEquals(var.asType(), type.asType())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java	Thu Feb 12 03:42:51 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1976 +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 java.util.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-import javax.lang.model.util.*;
-
-import com.oracle.truffle.api.dsl.*;
-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.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
-import com.oracle.truffle.dsl.processor.model.*;
-import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality;
-import com.oracle.truffle.dsl.processor.parser.*;
-import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard;
-
-class NodeBaseFactory {
-
-    private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode";
-
-    static final String EXECUTE_CHAINED = "executeChained0";
-    private static final String SPECIALIZE = "specialize0";
-    private static final String DSLSHARE_REWRITE = "rewrite";
-    private static final String DSLSHARE_FIND_ROOT = "findRoot";
-    private static final String DSLSHARE_REWRITE_TO_POLYMORHPIC = "rewriteToPolymorphic";
-    static final String EXECUTE_UNINITIALIZED = "executeUninitialized0";
-    private static final String REWRITE = "rewrite0";
-    private static final String CREATE_INFO = "createInfo0";
-    static final String CONTAINS_FALLBACK = "containsFallback";
-
-    static final String EMPTY_CLASS_ARRAY = "EMPTY_CLASS_ARRAY";
-
-    static final String METADATA_FIELD_NAME = "METADATA";
-
-    protected final ProcessorContext context;
-    protected final NodeData node;
-    protected final SpecializationData specialization;
-
-    public NodeBaseFactory(ProcessorContext context, NodeData node, SpecializationData specialization) {
-        this.context = context;
-        this.node = node;
-        this.specialization = specialization;
-    }
-
-    public CodeTypeElement create() {
-        CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, ABSTRACT), baseClassName(node), node.getNodeType());
-        clazz.getImplements().add(context.getTruffleTypes().getDslNode());
-
-        for (NodeChildData child : node.getChildren()) {
-            clazz.add(createChildField(child));
-
-            if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) {
-                ExecutableElement getter = (ExecutableElement) child.getAccessElement();
-                CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), getter);
-                method.getModifiers().remove(Modifier.ABSTRACT);
-                CodeTreeBuilder builder = method.createBuilder();
-                builder.startReturn().string("this.").string(child.getName()).end();
-                clazz.add(method);
-            }
-        }
-
-        for (NodeFieldData field : node.getFields()) {
-            if (!field.isGenerated()) {
-                continue;
-            }
-
-            clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), field.getType(), field.getName()));
-            if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) {
-                CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), field.getGetter());
-                method.getModifiers().remove(Modifier.ABSTRACT);
-                method.createBuilder().startReturn().string("this.").string(field.getName()).end();
-                clazz.add(method);
-            }
-        }
-
-        for (String assumption : node.getAssumptions()) {
-            clazz.add(createAssumptionField(assumption));
-        }
-
-        createConstructors(clazz);
-
-        SpecializationGroup rootGroup = createSpecializationGroups(node);
-
-        if (node.needsRewrites(context)) {
-            if (node.isPolymorphic(context)) {
-
-                CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0");
-                var.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getTruffleTypes().getChildAnnotation()));
-                clazz.add(var);
-
-                CodeExecutableElement genericCachedExecute = createCachedExecute(node.getPolymorphicSpecialization());
-                clazz.add(genericCachedExecute);
-
-            }
-
-            for (CodeExecutableElement method : createImplicitChildrenAccessors()) {
-                clazz.add(method);
-            }
-            clazz.add(createInfoMessage());
-            clazz.add(createMonomorphicRewrite());
-            clazz.add(createCreateSpecializationMethod(rootGroup));
-        }
-
-        clazz.add(createAdoptChildren0());
-        clazz.add(createGetMetadata0(true));
-        clazz.add(createUpdateTypes0());
-        clazz.add(createGetNext());
-
-        return clazz;
-    }
-
-    public static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
-        TypeElement type = ElementUtils.fromTypeMirror(nodeType);
-        List<ExecutableElement> constructors = new ArrayList<>();
-        for (ExecutableElement constructor : ElementFilter.constructorsIn(type.getEnclosedElements())) {
-            if (constructor.getModifiers().contains(PRIVATE)) {
-                continue;
-            }
-            if (isCopyConstructor(constructor)) {
-                continue;
-            }
-            constructors.add(constructor);
-        }
-
-        if (constructors.isEmpty()) {
-            CodeExecutableElement executable = new CodeExecutableElement(null, ElementUtils.getSimpleName(nodeType));
-            ElementUtils.setVisibility(executable.getModifiers(), ElementUtils.getVisibility(type.getModifiers()));
-            constructors.add(executable);
-        }
-
-        return constructors;
-    }
-
-    public static boolean isCopyConstructor(ExecutableElement element) {
-        if (element.getParameters().size() != 1) {
-            return false;
-        }
-        VariableElement var = element.getParameters().get(0);
-        TypeElement enclosingType = ElementUtils.findNearestEnclosingType(var);
-        if (ElementUtils.typeEquals(var.asType(), enclosingType.asType())) {
-            return true;
-        }
-        List<TypeElement> types = ElementUtils.getDirectSuperTypes(enclosingType);
-        for (TypeElement type : types) {
-            if (!(type instanceof CodeTypeElement)) {
-                // no copy constructors which are not generated types
-                return false;
-            }
-
-            if (ElementUtils.typeEquals(var.asType(), type.asType())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public SpecializationData getSpecialization() {
-        return specialization;
-    }
-
-    private Element createGetNext() {
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(Node.class), "getNext0");
-        CodeTreeBuilder builder = method.createBuilder();
-
-        if (node.isPolymorphic(context)) {
-            builder.startReturn().string("next0").end();
-        } else {
-            builder.returnNull();
-        }
-
-        return method;
-    }
-
-    protected final CodeExecutableElement createUpdateTypes0() {
-        ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(void.class), "updateTypes0");
-        method.getParameters().add(new CodeVariableElement(classArray, "types"));
-
-        if (getSpecialization().isPolymorphic()) {
-            CodeTreeBuilder builder = method.createBuilder();
-
-            int index = 0;
-            for (NodeExecutionData execution : getSpecialization().getNode().getChildExecutions()) {
-                String fieldName = polymorphicTypeName(execution);
-
-                builder.startStatement();
-                builder.string(fieldName).string(" = ").string("types[").string(String.valueOf(index)).string("]");
-                builder.end();
-                index++;
-            }
-        }
-
-        return method;
-    }
-
-    protected final CodeExecutableElement createGetMetadata0(boolean empty) {
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getDslMetadata(), "getMetadata0");
-        if (empty) {
-            method.createBuilder().startReturn().staticReference(context.getTruffleTypes().getDslMetadata(), "NONE").end();
-        } else {
-            method.createBuilder().startReturn().string(METADATA_FIELD_NAME).end();
-        }
-        return method;
-    }
-
-    private CodeExecutableElement createAdoptChildren0() {
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(void.class), "adoptChildren0");
-        method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "other"));
-        method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "newNext"));
-        CodeTreeBuilder builder = method.createBuilder();
-        List<NodeExecutionData> executions = node.getChildExecutions();
-
-        if (executions.size() > 0) {
-            builder.startIf().string("other == null").end().startBlock();
-            for (NodeExecutionData execution : executions) {
-                builder.startStatement().tree(createAccessChild(execution, "this")).string(" = null").end();
-            }
-            builder.end().startElseBlock();
-
-            String access;
-            if (executions.size() > 1) {
-                builder.declaration(baseClassName(node), "otherCast", builder.create().cast(baseClassName(node)).string("other"));
-                access = "otherCast";
-            } else {
-                assert executions.size() == 1;
-                access = "((" + baseClassName(node) + ") other)";
-            }
-            for (NodeExecutionData execution : executions) {
-                builder.startStatement().tree(createAccessChild(execution, "this")).string(" = ").tree(createAccessChild(execution, access)).end();
-            }
-
-            builder.end();
-        }
-
-        if (getSpecialization().getNode().isPolymorphic(context)) {
-            builder.startIf().string("newNext == null").end().startBlock();
-            builder.statement("this.next0 = null");
-            builder.end().startElseBlock();
-            builder.statement("this.next0 = (" + baseClassName(getSpecialization().getNode()) + ") newNext");
-            builder.end();
-        }
-
-        return method;
-    }
-
-    private List<CodeExecutableElement> createImplicitChildrenAccessors() {
-        List<Set<TypeData>> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null);
-        List<Set<TypeData>> expectTypes = new ArrayList<>(prototype);
-
-        for (ExecutableTypeData executableType : node.getExecutableTypes()) {
-            for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
-                Parameter parameter = executableType.getSignatureParameter(i);
-                if (i >= expectTypes.size()) {
-                    break;
-                }
-                Set<TypeData> types = expectTypes.get(i);
-                if (types == null) {
-                    types = new TreeSet<>();
-                    expectTypes.set(i, types);
-                }
-                types.add(parameter.getTypeSystemType());
-            }
-        }
-
-        List<CodeExecutableElement> methods = new ArrayList<>();
-        List<Set<TypeData>> visitedList = new ArrayList<>(prototype);
-        for (SpecializationData spec : node.getSpecializations()) {
-            int signatureIndex = -1;
-            for (Parameter param : spec.getParameters()) {
-                if (!param.getSpecification().isSignature()) {
-                    continue;
-                }
-                signatureIndex++;
-                Set<TypeData> visitedTypeData = visitedList.get(signatureIndex);
-                if (visitedTypeData == null) {
-                    visitedTypeData = new TreeSet<>();
-                    visitedList.set(signatureIndex, visitedTypeData);
-                }
-
-                if (visitedTypeData.contains(param.getTypeSystemType())) {
-                    continue;
-                }
-                visitedTypeData.add(param.getTypeSystemType());
-
-                Set<TypeData> expect = expectTypes.get(signatureIndex);
-                if (expect == null) {
-                    expect = Collections.emptySet();
-                }
-
-                methods.addAll(createExecuteChilds(param, expect));
-            }
-        }
-        return methods;
-    }
-
-    private CodeTree truffleBooleanOption(CodeTreeBuilder parent, String name) {
-        CodeTreeBuilder builder = parent.create();
-        builder.staticReference(context.getTruffleTypes().getTruffleOptions(), name);
-        return builder.build();
-    }
-
-    private void addInternalValueParameters(CodeExecutableElement executableMethod, TemplateMethod method, boolean forceFrame, boolean disableFrame, boolean evaluated) {
-        if (forceFrame && !disableFrame && method.getSpecification().findParameterSpec("frame") != null) {
-            executableMethod.addParameter(new CodeVariableElement(context.getTruffleTypes().getFrame(), "frameValue"));
-        }
-        for (Parameter parameter : method.getParameters()) {
-            ParameterSpec spec = parameter.getSpecification();
-            if ((disableFrame || forceFrame) && spec.getName().equals("frame")) {
-                continue;
-            }
-            if (spec.isLocal()) {
-                continue;
-            }
-
-            String name = valueName(parameter);
-            if (evaluated && spec.isSignature()) {
-                name = valueNameEvaluated(parameter);
-            }
-
-            executableMethod.addParameter(new CodeVariableElement(parameter.getType(), name));
-        }
-    }
-
-    private Element createInfoMessage() {
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), context.getType(String.class), CREATE_INFO);
-        method.addParameter(new CodeVariableElement(context.getType(String.class), "message"));
-        addInternalValueParameters(method, node.getGenericSpecialization(), false, false, false);
-
-        CodeTreeBuilder builder = method.createBuilder();
-
-        builder.startIf().tree(truffleBooleanOption(builder, TruffleTypes.OPTION_DETAILED_REWRITE_REASONS)).end();
-        builder.startBlock();
-
-        builder.startStatement().string("StringBuilder builder = new StringBuilder(message)").end();
-        builder.startStatement().startCall("builder", "append").doubleQuote(" (").end().end();
-
-        String sep = null;
-        for (Parameter parameter : node.getGenericSpecialization().getSignatureParameters()) {
-            builder.startStatement();
-            builder.string("builder");
-            if (sep != null) {
-                builder.startCall(".append").doubleQuote(sep).end();
-            }
-            builder.startCall(".append").doubleQuote(parameter.getLocalName()).end();
-            builder.startCall(".append").doubleQuote(" = ").end();
-            builder.startCall(".append").string(parameter.getLocalName()).end();
-            builder.end();
-
-            if (!ElementUtils.isPrimitive(parameter.getType())) {
-                builder.startIf().string(parameter.getLocalName() + " != null").end();
-                builder.startBlock();
-            }
-            builder.startStatement();
-            if (ElementUtils.isPrimitive(parameter.getType())) {
-                builder.startCall("builder.append").doubleQuote(" (" + ElementUtils.getSimpleName(parameter.getType()) + ")").end();
-            } else {
-                builder.startCall("builder.append").doubleQuote(" (").end();
-                builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end();
-                builder.startCall(".append").doubleQuote(")").end();
-            }
-            builder.end();
-            if (!ElementUtils.isPrimitive(parameter.getType())) {
-                builder.end();
-            }
-
-            sep = ", ";
-        }
-
-        builder.startStatement().startCall("builder", "append").doubleQuote(")").end().end();
-        builder.startReturn().string("builder.toString()").end();
-
-        builder.end();
-        builder.startElseBlock();
-        builder.startReturn().string("message").end();
-        builder.end();
-
-        return method;
-    }
-
-    private CodeExecutableElement createCachedExecute(SpecializationData polymorph) {
-        CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), EXECUTE_CHAINED);
-        addInternalValueParameters(cachedExecute, polymorph, true, false, false);
-
-        ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0);
-        boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(context);
-        if (sourceThrowsUnexpected && sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) {
-            sourceThrowsUnexpected = false;
-        }
-        if (sourceThrowsUnexpected) {
-            cachedExecute.getThrownTypes().add(context.getType(UnexpectedResultException.class));
-        }
-        return cachedExecute;
-
-    }
-
-    private void createConstructors(CodeTypeElement clazz) {
-        List<ExecutableElement> constructors = findUserConstructors(node.getNodeType());
-        ExecutableElement sourceSectionConstructor = null;
-        if (constructors.isEmpty()) {
-            clazz.add(createUserConstructor(clazz, null));
-        } else {
-            for (ExecutableElement constructor : constructors) {
-                clazz.add(createUserConstructor(clazz, constructor));
-                if (NodeParser.isSourceSectionConstructor(context, constructor)) {
-                    sourceSectionConstructor = constructor;
-                }
-            }
-        }
-        if (node.needsRewrites(context)) {
-            ExecutableElement copyConstructor = findCopyConstructor(node.getNodeType());
-            clazz.add(createCopyConstructor(clazz, copyConstructor, sourceSectionConstructor));
-        }
-    }
-
-    private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) {
-        CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
-        CodeTreeBuilder builder = method.createBuilder();
-
-        if (superConstructor != null) {
-            ElementUtils.setVisibility(method.getModifiers(), ElementUtils.getVisibility(superConstructor.getModifiers()));
-            for (VariableElement param : superConstructor.getParameters()) {
-                method.getParameters().add(CodeVariableElement.clone(param));
-            }
-            builder.startStatement().startSuperCall();
-            for (VariableElement param : superConstructor.getParameters()) {
-                builder.string(param.getSimpleName().toString());
-            }
-            builder.end().end();
-        }
-
-        for (VariableElement var : type.getFields()) {
-            if (var.getModifiers().contains(STATIC)) {
-                continue;
-            }
-            NodeChildData child = node.findChild(var.getSimpleName().toString());
-
-            if (child != null) {
-                method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName()));
-            } else {
-                method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString()));
-            }
-
-            builder.startStatement();
-            String fieldName = var.getSimpleName().toString();
-
-            CodeTree init = createStaticCast(builder, child, fieldName);
-
-            builder.string("this.").string(fieldName).string(" = ").tree(init);
-            builder.end();
-        }
-        return method;
-    }
-
-    private CodeTree createStaticCast(CodeTreeBuilder parent, NodeChildData child, String fieldName) {
-        NodeData parentNode = getSpecialization().getNode();
-        if (child != null) {
-            CreateCastData createCast = parentNode.findCast(child.getName());
-            if (createCast != null) {
-                return createTemplateMethodCall(parent, null, parentNode.getGenericSpecialization(), createCast, null, fieldName);
-            }
-        }
-        return CodeTreeBuilder.singleString(fieldName);
-    }
-
-    private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) {
-        CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
-        CodeTreeBuilder builder = method.createBuilder();
-        method.getParameters().add(new CodeVariableElement(type.asType(), "copy"));
-
-        if (superConstructor != null) {
-            builder.startStatement().startSuperCall().string("copy").end().end();
-        } else if (sourceSectionConstructor != null) {
-            builder.startStatement().startSuperCall().string("copy.getSourceSection()").end().end();
-        }
-
-        for (VariableElement var : type.getFields()) {
-            if (var.getModifiers().contains(STATIC) || !var.getModifiers().contains(FINAL)) {
-                continue;
-            }
-            final String varName = var.getSimpleName().toString();
-            final TypeMirror varType = var.asType();
-            if (ElementUtils.isAssignable(varType, context.getTruffleTypes().getNodeArray())) {
-                CodeTree size = builder.create().string("copy.", varName, ".length").build();
-                builder.startStatement().string("this.").string(varName).string(" = ").startNewArray((ArrayType) varType, size).end().end();
-            } else {
-                builder.startStatement().string("this.", varName, " = copy.", varName).end();
-            }
-        }
-
-        return method;
-    }
-
-    private CodeVariableElement createAssumptionField(String assumption) {
-        CodeVariableElement var = new CodeVariableElement(context.getTruffleTypes().getAssumption(), assumption);
-        var.getModifiers().add(Modifier.FINAL);
-        return var;
-    }
-
-    private CodeVariableElement createChildField(NodeChildData child) {
-        TypeMirror type = child.getNodeType();
-        CodeVariableElement var = new CodeVariableElement(type, child.getName());
-        var.getModifiers().add(Modifier.PROTECTED);
-
-        DeclaredType annotationType;
-        if (child.getCardinality() == Cardinality.MANY) {
-            var.getModifiers().add(Modifier.FINAL);
-            annotationType = context.getTruffleTypes().getChildrenAnnotation();
-        } else {
-            annotationType = context.getTruffleTypes().getChildAnnotation();
-        }
-
-        var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
-        return var;
-    }
-
-    private static SpecializationGroup createSpecializationGroups(final NodeData node) {
-        List<SpecializationData> specializations = node.getSpecializations();
-        List<SpecializationData> filteredSpecializations = new ArrayList<>();
-        for (SpecializationData current : specializations) {
-            if (current.isUninitialized() || current.isPolymorphic() || !current.isReachable()) {
-                continue;
-            }
-            filteredSpecializations.add(current);
-        }
-
-        return SpecializationGroup.create(filteredSpecializations);
-    }
-
-    protected final CodeExecutableElement createExecuteUninitialized() {
-        SpecializationData generic = node.getGenericSpecialization();
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), generic.getReturnType().getType(), EXECUTE_UNINITIALIZED);
-        addInternalValueParameters(method, generic, true, false, false);
-        CodeTreeBuilder builder = method.createBuilder();
-
-        boolean needsFrame = node.isFrameUsedByAnyGuard();
-        CodeTreeBuilder createSpecializationCall = builder.create();
-        createSpecializationCall.startCall(SPECIALIZE);
-        addInternalValueParameterNames(createSpecializationCall, generic, generic, null, needsFrame, !needsFrame, null);
-        createSpecializationCall.end();
-        builder.declaration(baseClassName(node), "newNode", createSpecializationCall);
-
-        if (generic.isReachable()) {
-            builder.startIf().string("newNode == null").end().startBlock();
-
-            builder.startIf().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "inInterpreter").end().end().startBlock();
-            builder.statement("containsFallback = true");
-            builder.end();
-            builder.tree(createGenericInvoke(builder, generic, generic));
-            builder.end();
-            builder.startElseBlock();
-            builder.tree(createDeoptimize(builder));
-            builder.end();
-        }
-
-        builder.startReturn();
-        builder.startStaticCall(context.getTruffleTypes().getDslShare(), "rewriteUninitialized").string("this").string("newNode").end();
-        builder.string(".").startCall(EXECUTE_CHAINED);
-        addInternalValueParameterNames(builder, generic, generic, null, true, false, null);
-        builder.end();
-        builder.end();
-
-        if (generic.isReachable()) {
-            builder.end();
-        }
-
-        return method;
-    }
-
-    private static CodeTree createInfoCall(CodeTreeBuilder parent, SpecializationData specialization, String reason) {
-        CodeTreeBuilder builder = parent.create();
-        builder.startCall(CREATE_INFO).string(reason);
-        addInternalValueParameterNames(builder, specialization, specialization, null, false, false, null);
-        builder.end();
-        return builder.build();
-    }
-
-    private CodeExecutableElement createMonomorphicRewrite() {
-        SpecializationData generic = node.getGenericSpecialization();
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), generic.getReturnType().getType(), REWRITE);
-        addInternalValueParameters(method, generic, true, false, false);
-        method.addParameter(new CodeVariableElement(context.getType(String.class), "reason"));
-
-        boolean needsFrame = node.isFrameUsedByAnyGuard();
-        CodeTreeBuilder builder = method.createBuilder();
-
-        builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end().end();
-        String baseClassName = baseClassName(getSpecialization().getNode());
-        CodeTreeBuilder createSpecializationCall = builder.create();
-        createSpecializationCall.startCall(SPECIALIZE);
-        addInternalValueParameterNames(createSpecializationCall, generic, generic, null, needsFrame, !needsFrame, null);
-        createSpecializationCall.end();
-        builder.declaration(baseClassName, "newNode", createSpecializationCall);
-
-        builder.startIf().string("newNode == null").end().startBlock();
-        builder.startStatement();
-        String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization());
-        builder.string("newNode = ").startNew(uninitializedName).string("this").end();
-        builder.end();
-        if (node.isFallbackReachable()) {
-            builder.startStatement().string("((", uninitializedName, ") newNode).containsFallback = true").end();
-        }
-        builder.end();
-
-        builder.startStatement();
-        builder.type(context.getType(String.class)).string(" message = ").tree(createInfoCall(builder, generic, "reason"));
-        builder.end();
-
-        builder.declaration(baseClassName, "returnNode",
-                        builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE).string("this").string("newNode").string("message").end().build());
-        builder.startIf().string("returnNode == null").end().startBlock();
-        builder.tree(createRewritePolymorphic(builder, "this"));
-        builder.end();
-
-        builder.startReturn();
-        builder.startCall("returnNode", EXECUTE_CHAINED);
-        addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, false, null);
-        builder.end();
-        builder.end();
-
-        return method;
-    }
-
-    private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, String currentNode) {
-        String polyClassName = nodePolymorphicClassName(node);
-        CodeTreeBuilder builder = parent.create();
-
-        builder.startStatement().string("returnNode = ");
-        builder.startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE_TO_POLYMORHPIC);
-        builder.string("this");
-        builder.tree(builder.create().startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string(currentNode).end().build());
-        builder.tree(builder.create().startNew(polyClassName).string(currentNode).end().build());
-        builder.startGroup().cast(baseClassName(node)).startCall("copy").end().end();
-        builder.string("newNode");
-        builder.string("message");
-        builder.end();
-        builder.end();
-
-        return builder.build();
-    }
-
-    private CodeExecutableElement createCreateSpecializationMethod(SpecializationGroup group) {
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), baseClassName(node)),
-                        SPECIALIZE);
-
-        final boolean needsFrame = node.isFrameUsedByAnyGuard();
-
-        if (!needsFrame) {
-            method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getTruffleTypes().getTruffleBoundary()));
-        }
-
-        addInternalValueParameters(method, node.getGenericSpecialization(), needsFrame, !needsFrame, false);
-        final CodeTreeBuilder builder = method.createBuilder();
-        builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, new CodeBlock<SpecializationData>() {
-
-            public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
-                return createCreateSpecializationMethodBody0(builder, current, needsFrame);
-            }
-        }, null, false, true, false, true));
-
-        emitUnreachableSpecializations(builder, node);
-
-        return method;
-    }
-
-    private CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current, boolean useDeoptimize) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        if (current.isFallback()) {
-            builder.startReturn().nullLiteral().end();
-        } else {
-            String className = nodeSpecializationClassName(current);
-            if (!current.getExcludedBy().isEmpty()) {
-                builder.startIf().string("!").startStaticCall(context.getTruffleTypes().getDslShare(), "isExcluded");
-                builder.string("this").string(nodeSpecializationClassName(current), ".", METADATA_FIELD_NAME).end().end();
-                builder.startBlock();
-            }
-
-            if (current.getNode().getGenericSpecialization().isReachable() && useDeoptimize) {
-                builder.tree(createDeoptimize(builder));
-            }
-            builder.startReturn();
-            builder.cast(baseClassName(getSpecialization().getNode()));
-            builder.startGroup().startCall(className, NodeFactoryFactory.FACTORY_METHOD_NAME).string("this");
-            for (Parameter param : current.getSignatureParameters()) {
-                NodeChildData child = param.getSpecification().getExecution().getChild();
-                List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
-                if (types.size() > 1) {
-                    builder.string(implicitTypeName(param));
-                }
-            }
-            builder.end().end();
-            builder.end();
-
-            if (!current.getExcludedBy().isEmpty()) {
-                builder.end();
-            }
-        }
-        return builder.build();
-
-    }
-
-    private static void emitUnreachableSpecializations(final CodeTreeBuilder builder, NodeData node) {
-        for (SpecializationData current : node.getSpecializations()) {
-            if (current.isReachable()) {
-                continue;
-            }
-            builder.string("// unreachable ").string(current.getId()).newLine();
-        }
-    }
-
-    protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final CodeBlock<SpecializationData> guardedblock,
-                    final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions, final boolean typedCasts, final boolean castForGuardsOnly) {
-        return guard(outerParent, source, group, new CodeBlock<Integer>() {
-
-            public CodeTree create(CodeTreeBuilder parent, Integer ifCount) {
-                CodeTreeBuilder builder = parent.create();
-
-                if (group.getSpecialization() != null) {
-                    builder.tree(guardedblock.create(builder, group.getSpecialization()));
-
-                    assert group.getChildren().isEmpty() : "missed a specialization";
-
-                } else {
-                    for (SpecializationGroup childGroup : group.getChildren()) {
-                        builder.tree(createExecuteTree(builder, source, childGroup, guardedblock, null, false, emitAssumptions, typedCasts, castForGuardsOnly));
-                    }
-                }
-
-                return builder.build();
-            }
-        }, elseBlock, forceElse, emitAssumptions, typedCasts, castForGuardsOnly);
-    }
-
-    private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, CodeBlock<Integer> bodyBlock, CodeTree elseBlock, boolean forceElse, boolean emitAssumptions,
-                    boolean typedCasts, boolean castForGuardsOnly) {
-        CodeTreeBuilder builder = parent.create();
-
-        int ifCount = emitGuards(builder, source, group, emitAssumptions, typedCasts, castForGuardsOnly);
-
-        if (isReachableGroup(group, ifCount)) {
-            builder.tree(bodyBlock.create(builder, ifCount));
-        }
-
-        builder.end(ifCount);
-
-        if (elseBlock != null) {
-            if (ifCount > 0 || forceElse) {
-                builder.tree(elseBlock);
-            }
-        }
-
-        return builder.build();
-    }
-
-    private static boolean isReachableGroup(SpecializationGroup group, int ifCount) {
-        if (ifCount != 0) {
-            return true;
-        }
-        SpecializationGroup previous = group.getPreviousGroup();
-        if (previous == null || previous.findElseConnectableGuards().isEmpty()) {
-            return true;
-        }
-
-        /*
-         * Hacky else case. In this case the specialization is not reachable due to previous else
-         * branch. This is only true if the minimum state is not checked.
-         */
-        if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() &&
-                        (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) {
-        CodeTreeBuilder guardsBuilder = builder.create();
-        CodeTreeBuilder castBuilder = builder.create();
-        CodeTreeBuilder guardsCastBuilder = builder.create();
-
-        String guardsAnd = "";
-        String guardsCastAnd = "";
-
-        if (emitAssumptions) {
-            for (String assumption : group.getAssumptions()) {
-                guardsBuilder.string(guardsAnd);
-                guardsBuilder.string("this");
-                guardsBuilder.string(".").string(assumption).string(".isValid()");
-                guardsAnd = " && ";
-            }
-        }
-
-        for (TypeGuard typeGuard : group.getTypeGuards()) {
-            Parameter valueParam = source.getSignatureParameter(typeGuard.getSignatureIndex());
-
-            if (valueParam == null) {
-                /*
-                 * If used inside a execute evaluated method then the value param may not exist. In
-                 * that case we assume that the value is executed generic or of the current
-                 * specialization.
-                 */
-                if (group.getSpecialization() != null) {
-                    valueParam = group.getSpecialization().getSignatureParameter(typeGuard.getSignatureIndex());
-                } else {
-                    valueParam = node.getGenericSpecialization().getSignatureParameter(typeGuard.getSignatureIndex());
-                }
-            }
-
-            NodeExecutionData execution = valueParam.getSpecification().getExecution();
-            CodeTree implicitGuard = createTypeGuard(guardsBuilder, execution, valueParam, typeGuard.getType(), typedCasts);
-            if (implicitGuard != null) {
-                guardsBuilder.string(guardsAnd);
-                guardsBuilder.tree(implicitGuard);
-                guardsAnd = " && ";
-            }
-
-            CodeTree implicitGetType = null;
-            if (castForGuardsOnly) {
-                implicitGetType = createGetImplicitType(builder, execution, valueParam, typeGuard.getType());
-            }
-
-            boolean performCast = true;
-            if (castForGuardsOnly) {
-                // if cast for guards we just cast if the type guard is used inside a guard.
-                performCast = group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard);
-            }
-
-            if (performCast) {
-                CodeTree cast = createCast(castBuilder, execution, valueParam, typeGuard.getType(), typedCasts);
-                if (cast != null) {
-                    castBuilder.tree(cast);
-                }
-            }
-            if (implicitGetType != null) {
-                castBuilder.tree(implicitGetType);
-            }
-        }
-        List<GuardExpression> elseGuards = group.findElseConnectableGuards();
-
-        for (GuardExpression guard : group.getGuards()) {
-            if (elseGuards.contains(guard)) {
-                continue;
-            }
-
-            if (needsTypeGuard(source, group, guard)) {
-                guardsCastBuilder.tree(createMethodGuard(builder, guardsCastAnd, source, guard));
-                guardsCastAnd = " && ";
-            } else {
-                guardsBuilder.tree(createMethodGuard(builder, guardsAnd, source, guard));
-                guardsAnd = " && ";
-            }
-        }
-
-        int ifCount = startGuardIf(builder, guardsBuilder.build(), 0, elseGuards);
-        builder.tree(castBuilder.build());
-        ifCount = startGuardIf(builder, guardsCastBuilder.build(), ifCount, elseGuards);
-        return ifCount;
-    }
-
-    private static int startGuardIf(CodeTreeBuilder builder, CodeTree condition, int ifCount, List<GuardExpression> elseGuard) {
-        int newIfCount = ifCount;
-
-        if (!condition.isEmpty()) {
-            if (ifCount == 0 && !elseGuard.isEmpty()) {
-                builder.startElseIf();
-            } else {
-                builder.startIf();
-            }
-            builder.tree(condition);
-            builder.end().startBlock();
-            newIfCount++;
-        } else if (ifCount == 0 && !elseGuard.isEmpty()) {
-            builder.startElseBlock();
-            newIfCount++;
-        }
-        return newIfCount;
-    }
-
-    private static boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardExpression guard) {
-        for (Parameter parameter : guard.getResolvedGuard().getParameters()) {
-            if (!parameter.getSpecification().isSignature()) {
-                continue;
-            }
-
-            int signatureIndex = source.getNode().getChildExecutions().indexOf(parameter.getSpecification().getExecution());
-            if (signatureIndex == -1) {
-                continue;
-            }
-
-            TypeGuard typeGuard = group.findTypeGuard(signatureIndex);
-            if (typeGuard != null) {
-                TypeData requiredType = typeGuard.getType();
-
-                Parameter sourceParameter = source.findParameter(parameter.getLocalName());
-                if (sourceParameter == null) {
-                    sourceParameter = source.getNode().getGenericSpecialization().findParameter(parameter.getLocalName());
-                }
-
-                if (ElementUtils.needsCastTo(sourceParameter.getType(), requiredType.getPrimitiveType())) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType, boolean typedCasts) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        TypeData sourceType = source.getTypeSystemType();
-
-        if (!sourceType.needsCastTo(targetType)) {
-            return null;
-        }
-
-        builder.startGroup();
-
-        if (execution.isShortCircuit()) {
-            Parameter shortCircuit = source.getPreviousParameter();
-            assert shortCircuit != null;
-            builder.string("(");
-            builder.string("!").string(valueName(shortCircuit));
-            builder.string(" || ");
-        }
-
-        List<TypeData> types = getSpecialization().getNode().getTypeSystem().lookupSourceTypes(targetType);
-        if (types.size() > 1) {
-            String castTypeName = null;
-            if (typedCasts) {
-                castTypeName = implicitTypeName(source);
-            }
-            CodeTree check;
-            if (castTypeName == null) {
-                check = TypeSystemCodeGenerator.implicitCheck(targetType, CodeTreeBuilder.singleString(valueName(source)), null);
-            } else {
-                check = TypeSystemCodeGenerator.implicitCheck(targetType, CodeTreeBuilder.singleString(valueName(source)), castTypeName);
-            }
-            builder.tree(check);
-        } else {
-            builder.tree(TypeSystemCodeGenerator.check(targetType, CodeTreeBuilder.singleString(valueName(source))));
-        }
-
-        if (execution.isShortCircuit()) {
-            builder.string(")");
-        }
-
-        builder.end(); // group
-
-        return builder.build();
-    }
-
-    // TODO merge redundancies with #createTypeGuard
-    private CodeTree createCast(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType, boolean typedCasts) {
-        TypeData sourceType = source.getTypeSystemType();
-
-        if (!sourceType.needsCastTo(targetType)) {
-            return null;
-        }
-
-        CodeTree condition = null;
-        if (execution.isShortCircuit()) {
-            Parameter shortCircuit = source.getPreviousParameter();
-            assert shortCircuit != null;
-            condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
-        }
-
-        CodeTree cast;
-        List<TypeData> types = getSpecialization().getNode().getTypeSystem().lookupSourceTypes(targetType);
-        if (types.size() > 1) {
-            String castTypeName = null;
-            if (typedCasts) {
-                castTypeName = implicitTypeName(source);
-            }
-            cast = TypeSystemCodeGenerator.implicitCast(targetType, CodeTreeBuilder.singleString(valueName(source)), castTypeName);
-        } else {
-            cast = TypeSystemCodeGenerator.cast(targetType, valueName(source));
-        }
-
-        CodeTreeBuilder builder = parent.create();
-        builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, cast));
-
-        return builder.build();
-    }
-
-    private CodeTree createGetImplicitType(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType) {
-        CodeTree condition = null;
-        if (execution.isShortCircuit()) {
-            Parameter shortCircuit = source.getPreviousParameter();
-            assert shortCircuit != null;
-            condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
-        }
-
-        CodeTreeBuilder builder = parent.create();
-        List<TypeData> types = getSpecialization().getNode().getTypeSystem().lookupSourceTypes(targetType);
-        if (types.size() > 1) {
-            CodeTree castType = TypeSystemCodeGenerator.implicitType(targetType, CodeTreeBuilder.singleString(valueName(source)));
-            builder.tree(createLazyAssignment(builder, implicitTypeName(source), context.getType(Class.class), condition, castType));
-        }
-        return builder.build();
-    }
-
-    private static CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardExpression guard) {
-        CodeTreeBuilder builder = parent.create();
-        builder.string(prefix);
-        if (guard.isNegated()) {
-            builder.string("!");
-        }
-        builder.tree(createTemplateMethodCall(builder, null, source, guard.getResolvedGuard(), null));
-        return builder.build();
-    }
-
-    protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        if (current.getMethod() == null) {
-            emitEncounteredSynthetic(builder, getSpecialization().getNode(), current);
-        } else {
-            builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end();
-        }
-
-        return encloseThrowsWithFallThrough(parent, current, builder.build());
-    }
-
-    private CodeTree encloseThrowsWithFallThrough(CodeTreeBuilder parent, SpecializationData current, CodeTree tree) {
-        if (current.getExceptions().isEmpty()) {
-            return tree;
-        }
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        builder.startTryBlock();
-        builder.tree(tree);
-        for (SpecializationThrowsData exception : current.getExceptions()) {
-            builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx");
-            builder.tree(createDeoptimize(builder));
-            builder.tree(createCallRewriteMonomorphic(builder, false, current.getNode().getGenericSpecialization().getReturnType().getTypeSystemType(), null,
-                            "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass())));
-        }
-        builder.end();
-
-        return builder.build();
-    }
-
-    protected CodeTree createCastingExecute(CodeTreeBuilder parent, ExecutableTypeData executable, ExecutableTypeData castExecutable) {
-        TypeData type = executable.getType();
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        TypeData primaryType = castExecutable.getType();
-
-        boolean needsTry = castExecutable.hasUnexpectedValue(context);
-        boolean returnVoid = type.isVoid();
-
-        List<Parameter> executeParameters = new ArrayList<>();
-        for (Parameter sourceParameter : executable.getSignatureParameters()) {
-            Parameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName());
-            if (targetParameter != null) {
-                executeParameters.add(targetParameter);
-            }
-        }
-
-        // execute names are enforced no cast
-        String[] executeParameterNames = new String[executeParameters.size()];
-        for (int i = 0; i < executeParameterNames.length; i++) {
-            executeParameterNames[i] = valueName(executeParameters.get(i));
-        }
-
-        builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null));
-        boolean hasUnexpected = executable.hasUnexpectedValue(context);
-
-        CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null, executeParameterNames);
-        if (needsTry) {
-            if (!returnVoid) {
-                builder.declaration(primaryType.getPrimitiveType(), "value");
-            }
-            builder.startTryBlock();
-
-            if (returnVoid) {
-                builder.statement(primaryExecuteCall);
-            } else {
-                builder.startStatement();
-                builder.string("value = ");
-                builder.tree(primaryExecuteCall);
-                builder.end();
-            }
-
-            builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
-            if (returnVoid) {
-                builder.string("// ignore").newLine();
-            } else {
-                builder.startReturn();
-                builder.tree(createExpectExecutableType(specialization.getNode().getTypeSystem().getGenericTypeData(), hasUnexpected, executable.getType(),
-                                CodeTreeBuilder.singleString("ex.getResult()")));
-                builder.end();
-            }
-            builder.end();
-
-            if (!returnVoid) {
-                builder.startReturn();
-                builder.tree(createExpectExecutableType(castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), CodeTreeBuilder.singleString("value")));
-                builder.end();
-            }
-        } else {
-            if (returnVoid) {
-                builder.statement(primaryExecuteCall);
-            } else {
-                builder.startReturn();
-                builder.tree(createExpectExecutableType(castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), primaryExecuteCall));
-                builder.end();
-            }
-        }
-
-        return builder.build();
-    }
-
-    private static CodeTree createExpectExecutableType(TypeData sourceType, boolean hasUnexpected, TypeData exepctedType, CodeTree value) {
-        return createCastType(sourceType, exepctedType, hasUnexpected, value);
-    }
-
-    protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData currentSpecialization, List<Parameter> targetParameters,
-                    Parameter unexpectedParameter) {
-        CodeTreeBuilder builder = parent.create();
-        for (Parameter targetParameter : targetParameters) {
-            if (!targetParameter.getSpecification().isSignature()) {
-                continue;
-            }
-            NodeExecutionData execution = targetParameter.getSpecification().getExecution();
-            CodeTree executionExpressions = createExecuteChild(builder, execution, sourceExecutable, targetParameter, unexpectedParameter);
-            CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, currentSpecialization, sourceExecutable, targetParameter, execution.isShortCircuit(),
-                            unexpectedParameter);
-            CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, currentSpecialization, targetParameter, unexpectedParameter);
-
-            if (shortCircuitTree == executionExpressions) {
-                if (containsNewLine(executionExpressions)) {
-                    builder.declaration(targetParameter.getType(), valueName(targetParameter));
-                    builder.tree(shortCircuitTree);
-                } else {
-                    builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end();
-                }
-            } else {
-                builder.tree(shortCircuitTree);
-            }
-
-        }
-        return builder.build();
-    }
-
-    private ExecutableTypeData resolveExecutableType(NodeExecutionData execution, TypeData type) {
-        ExecutableTypeData targetExecutable = execution.getChild().findExecutableType(type);
-        if (targetExecutable == null) {
-            targetExecutable = execution.getChild().findAnyGenericExecutableType(context);
-        }
-        return targetExecutable;
-    }
-
-    private CodeTree createExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, Parameter targetParameter, Parameter unexpectedParameter) {
-        if (specialization.isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) {
-            List<TypeData> possiblePolymorphicTypes = lookupPolymorphicTargetTypes(targetParameter);
-            if (possiblePolymorphicTypes.size() > 1) {
-                CodeTreeBuilder builder = parent.create();
-
-                boolean elseIf = false;
-                for (TypeData possiblePolymoprhicType : possiblePolymorphicTypes) {
-                    if (possiblePolymoprhicType.isGeneric()) {
-                        continue;
-                    }
-                    elseIf = builder.startIf(elseIf);
-
-                    Parameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
-                    TypeData sourceType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
-                    builder.string(polymorphicTypeName(targetParameter.getSpecification().getExecution())).string(" == ").typeLiteral(possiblePolymoprhicType.getPrimitiveType());
-                    builder.end().startBlock();
-                    builder.startStatement();
-                    builder.tree(createExecuteChildExpression(parent, execution, sourceType, new Parameter(targetParameter, possiblePolymoprhicType), unexpectedParameter, null));
-                    builder.end();
-                    builder.end();
-                }
-
-                builder.startElseBlock();
-                builder.startStatement().tree(createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter)).end();
-                builder.end();
-
-                return builder.build();
-            }
-        }
-        return createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter);
-    }
-
-    protected static final List<Parameter> getImplicitTypeParameters(SpecializationData model) {
-        List<Parameter> parameter = new ArrayList<>();
-        for (Parameter param : model.getSignatureParameters()) {
-            NodeChildData child = param.getSpecification().getExecution().getChild();
-            List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
-            if (types.size() > 1) {
-                parameter.add(param);
-            }
-        }
-        return parameter;
-    }
-
-    private List<TypeData> lookupPolymorphicTargetTypes(Parameter param) {
-        Set<TypeData> possiblePolymorphicTypes = new HashSet<>();
-        for (SpecializationData otherSpecialization : specialization.getNode().getSpecializations()) {
-            if (!otherSpecialization.isSpecialized()) {
-                continue;
-            }
-            Parameter otherParameter = otherSpecialization.findParameter(param.getLocalName());
-            if (otherParameter != null) {
-                possiblePolymorphicTypes.add(otherParameter.getTypeSystemType());
-            }
-        }
-        List<TypeData> types = new ArrayList<>(possiblePolymorphicTypes);
-        Collections.sort(types);
-        return types;
-    }
-
-    private CodeTree createExecuteChildImplicit(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, Parameter param, Parameter unexpectedParameter) {
-        CodeTreeBuilder builder = parent.create();
-        Parameter sourceParameter = sourceExecutable.findParameter(param.getLocalName());
-        String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null);
-        if (childExecuteName != null) {
-            builder.string(valueName(param));
-            builder.string(" = ");
-            builder.startCall(childExecuteName);
-
-            for (Parameter parameters : sourceExecutable.getParameters()) {
-                if (parameters.getSpecification().isSignature()) {
-                    continue;
-                }
-                builder.string(parameters.getLocalName());
-            }
-
-            if (sourceParameter != null) {
-                builder.string(valueNameEvaluated(sourceParameter));
-            }
-
-            builder.string(implicitTypeName(param));
-
-            builder.end();
-        } else {
-            List<TypeData> sourceTypes = execution.getChild().getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
-            TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
-            if (sourceTypes.size() > 1) {
-                builder.tree(createExecuteChildImplicitExpressions(parent, param, expectType));
-            } else {
-                builder.tree(createExecuteChildExpression(parent, execution, expectType, param, unexpectedParameter, null));
-            }
-        }
-        return builder.build();
-    }
-
-    private static String createExecuteChildMethodName(Parameter param, boolean expect) {
-        NodeExecutionData execution = param.getSpecification().getExecution();
-        NodeChildData child = execution.getChild();
-        if (child.getExecuteWith().size() > 0) {
-            return null;
-        }
-        List<TypeData> sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
-        if (sourceTypes.size() <= 1) {
-            return null;
-        }
-        String prefix = expect ? "expect" : "execute";
-        String suffix = execution.getIndex() > -1 ? String.valueOf(execution.getIndex()) : "";
-        return prefix + ElementUtils.firstLetterUpperCase(child.getName()) + ElementUtils.firstLetterUpperCase(ElementUtils.getTypeId(param.getType())) + suffix;
-    }
-
-    private List<CodeExecutableElement> createExecuteChilds(Parameter param, Set<TypeData> expectTypes) {
-        CodeExecutableElement executeMethod = createExecuteChild(param, null);
-        if (executeMethod == null) {
-            return Collections.emptyList();
-        }
-        List<CodeExecutableElement> childs = new ArrayList<>();
-        childs.add(executeMethod);
-
-        for (TypeData expectType : expectTypes) {
-            CodeExecutableElement method = createExecuteChild(param, expectType);
-            if (method != null) {
-                childs.add(method);
-            }
-        }
-        return childs;
-    }
-
-    private CodeExecutableElement createExecuteChild(Parameter param, TypeData expectType) {
-        String childExecuteName = createExecuteChildMethodName(param, expectType != null);
-        if (childExecuteName == null) {
-            return null;
-        }
-
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC : FINAL), param.getType(), childExecuteName);
-        method.getThrownTypes().add(context.getTruffleTypes().getUnexpectedValueException());
-        method.addParameter(new CodeVariableElement(context.getTruffleTypes().getFrame(), "frameValue"));
-        if (expectType != null) {
-            method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param)));
-        }
-        method.addParameter(new CodeVariableElement(context.getType(Class.class), implicitTypeName(param)));
-
-        CodeTreeBuilder builder = method.createBuilder();
-        builder.declaration(param.getType(), valueName(param));
-        builder.tree(createExecuteChildImplicitExpressions(builder, param, expectType));
-        builder.startReturn().string(valueName(param)).end();
-
-        return method;
-    }
-
-    private CodeTree createExecuteChildImplicitExpressions(CodeTreeBuilder parent, Parameter targetParameter, TypeData expectType) {
-        CodeTreeBuilder builder = parent.create();
-        NodeExecutionData execution = targetParameter.getSpecification().getExecution();
-        List<TypeData> sourceTypes = node.getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType());
-        boolean elseIf = false;
-        int index = 0;
-        for (TypeData sourceType : sourceTypes) {
-            if (index < sourceTypes.size() - 1) {
-                elseIf = builder.startIf(elseIf);
-                builder.string(implicitTypeName(targetParameter)).string(" == ").typeLiteral(sourceType.getPrimitiveType());
-                builder.end();
-                builder.startBlock();
-            } else {
-                builder.startElseBlock();
-            }
-
-            ExecutableTypeData implictExecutableTypeData = execution.getChild().findExecutableType(sourceType);
-            if (implictExecutableTypeData == null) {
-                /*
-                 * For children with executeWith.size() > 0 an executable type may not exist so use
-                 * the generic executable type which is guaranteed to exist. An expect call is
-                 * inserted automatically by #createExecuteExpression.
-                 */
-                implictExecutableTypeData = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size());
-            }
-
-            ImplicitCastData cast = execution.getChild().getNodeData().getTypeSystem().lookupCast(sourceType, targetParameter.getTypeSystemType());
-            CodeTree execute = createExecuteChildExpression(builder, execution, expectType, targetParameter, null, cast);
-            builder.statement(execute);
-            builder.end();
-            index++;
-        }
-        return builder.build();
-    }
-
-    private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData execution, TypeData sourceParameterType, Parameter targetParameter, Parameter unexpectedParameter,
-                    ImplicitCastData cast) {
-        // assignments: targetType <- castTargetType <- castSourceType <- sourceType
-        TypeData sourceType = sourceParameterType;
-        TypeData targetType = targetParameter.getTypeSystemType();
-        TypeData castSourceType = targetType;
-        TypeData castTargetType = targetType;
-
-        if (cast != null) {
-            castSourceType = cast.getSourceType();
-            castTargetType = cast.getTargetType();
-        }
-
-        CodeTree expression;
-        if (sourceType == null) {
-            ExecutableTypeData targetExecutable = resolveExecutableType(execution, castSourceType);
-            expression = createExecuteChildExpression(parent, execution, targetExecutable, unexpectedParameter);
-            sourceType = targetExecutable.getType();
-        } else {
-            expression = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter));
-        }
-
-        // target = expectTargetType(implicitCast(expectCastSourceType(source)))
-        expression = createExpectType(sourceType, castSourceType, expression);
-        expression = createImplicitCast(cast, expression);
-        expression = createExpectType(castTargetType, targetType, expression);
-
-        CodeTreeBuilder builder = parent.create();
-        builder.string(valueName(targetParameter));
-        builder.string(" = ");
-        builder.tree(expression);
-        return builder.build();
-    }
-
-    private static CodeTree createImplicitCast(ImplicitCastData cast, CodeTree expression) {
-        if (cast == null) {
-            return expression;
-        }
-        return TypeSystemCodeGenerator.invokeImplicitCast(cast, expression);
-    }
-
-    private boolean containsNewLine(CodeTree tree) {
-        if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) {
-            return true;
-        }
-
-        List<CodeTree> enclosing = tree.getEnclosedElements();
-        if (enclosing != null) {
-            for (CodeTree codeTree : enclosing) {
-                if (containsNewLine(codeTree)) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    private boolean hasUnexpected(Parameter sourceParameter, Parameter targetParameter, Parameter unexpectedParameter) {
-        NodeExecutionData execution = targetParameter.getSpecification().getExecution();
-
-        if (getSpecialization().isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) {
-            // check for other polymorphic types
-            List<TypeData> polymorphicTargetTypes = lookupPolymorphicTargetTypes(targetParameter);
-            if (polymorphicTargetTypes.size() > 1) {
-                for (TypeData polymorphicTargetType : polymorphicTargetTypes) {
-                    if (hasUnexpectedType(execution, sourceParameter, polymorphicTargetType)) {
-                        return true;
-                    }
-                }
-            }
-        }
-
-        if (hasUnexpectedType(execution, sourceParameter, targetParameter.getTypeSystemType())) {
-            return true;
-        }
-        return false;
-    }
-
-    private boolean hasUnexpectedType(NodeExecutionData execution, Parameter sourceParameter, TypeData targetType) {
-        List<TypeData> implicitSourceTypes = getSpecialization().getNode().getTypeSystem().lookupSourceTypes(targetType);
-
-        for (TypeData implicitSourceType : implicitSourceTypes) {
-            TypeData sourceType;
-            ExecutableTypeData targetExecutable = resolveExecutableType(execution, implicitSourceType);
-            if (sourceParameter != null) {
-                sourceType = sourceParameter.getTypeSystemType();
-            } else {
-                if (targetExecutable.hasUnexpectedValue(context)) {
-                    return true;
-                }
-                sourceType = targetExecutable.getType();
-            }
-
-            ImplicitCastData cast = getSpecialization().getNode().getTypeSystem().lookupCast(implicitSourceType, targetType);
-            if (cast != null) {
-                if (cast.getSourceType().needsCastTo(targetType)) {
-                    return true;
-                }
-            }
-
-            if (sourceType.needsCastTo(targetType)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, SpecializationData currentSpecialization, ExecutableTypeData currentExecutable, Parameter param,
-                    boolean shortCircuit, Parameter unexpectedParameter) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        Parameter sourceParameter = currentExecutable.findParameter(param.getLocalName());
-        boolean unexpected = hasUnexpected(sourceParameter, param, unexpectedParameter);
-        if (!unexpected) {
-            return body;
-        }
-
-        if (!shortCircuit) {
-            builder.declaration(param.getType(), valueName(param));
-        }
-        builder.startTryBlock();
-
-        if (containsNewLine(body)) {
-            builder.tree(body);
-        } else {
-            builder.statement(body);
-        }
-
-        builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
-        SpecializationData generic = currentSpecialization.getNode().getGenericSpecialization();
-        Parameter genericParameter = generic.findParameter(param.getLocalName());
-
-        List<Parameter> genericParameters = generic.getParametersAfter(genericParameter);
-        builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter));
-        if (currentSpecialization.isPolymorphic()) {
-            builder.tree(createReturnOptimizeTypes(builder, currentExecutable, currentSpecialization, param));
-        } else {
-            builder.tree(createCallRewriteMonomorphic(builder, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), param, "Expected " + param.getLocalName() + " instanceof " +
-                            ElementUtils.getSimpleName(param.getType())));
-        }
-        builder.end(); // catch block
-
-        return builder.build();
-    }
-
-    private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData currentSpecialization, Parameter param) {
-        SpecializationData polymorphic = node.getPolymorphicSpecialization();
-
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        builder.startStatement().string(polymorphicTypeName(param.getSpecification().getExecution())).string(" = ").typeLiteral(context.getType(Object.class)).end();
-
-        builder.startReturn();
-
-        CodeTreeBuilder execute = new CodeTreeBuilder(builder);
-        execute.startCall("next0", EXECUTE_CHAINED);
-        addInternalValueParameterNames(execute, currentSpecialization, polymorphic, param.getLocalName(), true, false, null);
-        execute.end();
-
-        TypeData sourceType = polymorphic.getReturnType().getTypeSystemType();
-
-        builder.tree(createExpectExecutableType(sourceType, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), execute.build()));
-
-        builder.end();
-        return builder.build();
-    }
-
-    private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, Parameter unexpectedParameter) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        if (targetExecution != null) {
-            builder.tree(createAccessChild(targetExecution, null));
-            builder.string(".");
-        }
-
-        builder.startCall(targetExecutable.getMethodName());
-
-        // TODO this should be merged with #createTemplateMethodCall
-        int index = 0;
-        for (Parameter parameter : targetExecutable.getParameters()) {
-
-            if (!parameter.getSpecification().isSignature()) {
-                builder.string(parameter.getLocalName());
-            } else {
-
-                if (index < targetExecution.getChild().getExecuteWith().size()) {
-                    NodeChildData child = targetExecution.getChild().getExecuteWith().get(index);
-
-                    ParameterSpec spec = getSpecialization().getSpecification().findParameterSpec(child.getName());
-                    List<Parameter> specializationParams = getSpecialization().findParameters(spec);
-
-                    if (specializationParams.isEmpty()) {
-                        builder.defaultValue(parameter.getType());
-                        continue;
-                    }
-
-                    Parameter specializationParam = specializationParams.get(0);
-
-                    TypeData targetType = parameter.getTypeSystemType();
-                    TypeData sourceType = specializationParam.getTypeSystemType();
-                    String localName = specializationParam.getLocalName();
-
-                    if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) {
-                        localName = "ex.getResult()";
-                        sourceType = getSpecialization().getNode().getTypeSystem().getGenericTypeData();
-                    }
-
-                    CodeTree value = CodeTreeBuilder.singleString(localName);
-
-                    if (sourceType.needsCastTo(targetType)) {
-                        value = TypeSystemCodeGenerator.cast(targetType, value);
-                    }
-                    builder.tree(value);
-                } else {
-                    builder.defaultValue(parameter.getType());
-                }
-                index++;
-            }
-        }
-
-        builder.end();
-
-        return builder.build();
-    }
-
-    private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData currentSpecialization, Parameter parameter, Parameter exceptionParam) {
-        NodeExecutionData execution = parameter.getSpecification().getExecution();
-        if (execution == null || !execution.isShortCircuit()) {
-            return body;
-        }
-
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        Parameter shortCircuitParam = currentSpecialization.getPreviousParam(parameter);
-        builder.tree(createShortCircuitValue(builder, currentSpecialization, execution, shortCircuitParam, exceptionParam));
-        builder.declaration(parameter.getType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
-        builder.startIf().string(shortCircuitParam.getLocalName()).end();
-        builder.startBlock();
-
-        if (containsNewLine(body)) {
-            builder.tree(body);
-        } else {
-            builder.statement(body);
-        }
-        builder.end();
-
-        return builder.build();
-    }
-
-    private static CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeExecutionData execution, Parameter shortCircuitParam, Parameter exceptionParam) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        int shortCircuitIndex = 0;
-        for (NodeExecutionData otherExectuion : specialization.getNode().getChildExecutions()) {
-            if (otherExectuion.isShortCircuit()) {
-                if (otherExectuion == execution) {
-                    break;
-                }
-                shortCircuitIndex++;
-            }
-        }
-
-        builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
-        ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
-        builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
-        builder.end(); // statement
-
-        return builder.build();
-    }
-
-    protected CodeTree createCallRewriteMonomorphic(CodeTreeBuilder parent, boolean hasUnexpected, TypeData returnType, Parameter exceptionParam, String reason) {
-        SpecializationData generic = node.getGenericSpecialization();
-        CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
-        specializeCall.startCall(REWRITE);
-        addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, false, null);
-        specializeCall.doubleQuote(reason);
-        specializeCall.end().end();
-
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        builder.startReturn();
-        builder.tree(createExpectExecutableType(generic.getReturnType().getTypeSystemType(), hasUnexpected, returnType, specializeCall.build()));
-        builder.end();
-
-        return builder.build();
-    }
-
-    static String valueNameEvaluated(Parameter targetParameter) {
-        return valueName(targetParameter) + "Evaluated";
-    }
-
-    static String implicitTypeName(Parameter param) {
-        return param.getLocalName() + "ImplicitType";
-    }
-
-    static String polymorphicTypeName(NodeExecutionData param) {
-        return param.getName() + "PolymorphicType";
-    }
-
-    static String valueName(Parameter param) {
-        return param.getLocalName();
-    }
-
-    private static CodeTree createAccessChild(NodeExecutionData targetExecution, String thisReference) {
-        String reference = thisReference;
-        if (reference == null) {
-            reference = "this";
-        }
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        Element accessElement = targetExecution.getChild().getAccessElement();
-        if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) {
-            builder.string(reference).string(".").string(targetExecution.getChild().getName());
-        } else if (accessElement.getKind() == ElementKind.FIELD) {
-            builder.string(reference).string(".").string(accessElement.getSimpleName().toString());
-        } else {
-            throw new AssertionError();
-        }
-        if (targetExecution.isIndexed()) {
-            builder.string("[" + targetExecution.getIndex() + "]");
-        }
-        return builder.build();
-    }
-
-    private static String castValueName(Parameter parameter) {
-        return valueName(parameter) + "Cast";
-    }
-
-    static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean disableFrame,
-                    Map<String, String> customNames) {
-        if (forceFrame && !disableFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
-            builder.string("frameValue");
-        }
-        for (Parameter parameter : specialization.getParameters()) {
-            ParameterSpec spec = parameter.getSpecification();
-            if ((disableFrame || forceFrame) && spec.getName().equals("frame")) {
-                continue;
-            }
-
-            if (parameter.getSpecification().isLocal()) {
-                continue;
-            }
-
-            Parameter sourceParameter = source.findParameter(parameter.getLocalName());
-
-            if (customNames != null && customNames.containsKey(parameter.getLocalName())) {
-                builder.string(customNames.get(parameter.getLocalName()));
-            } else if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) {
-                builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
-            } else if (sourceParameter != null) {
-                builder.string(valueName(sourceParameter, parameter));
-            } else {
-                builder.string(valueName(parameter));
-            }
-        }
-    }
-
-    private static String valueName(Parameter sourceParameter, Parameter targetParameter) {
-        if (!sourceParameter.getSpecification().isSignature()) {
-            return valueName(targetParameter);
-        } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
-            if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) {
-                return castValueName(targetParameter);
-            }
-        }
-        return valueName(targetParameter);
-    }
-
-    static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName,
-                    String... customSignatureValueNames) {
-        CodeTreeBuilder builder = parent.create();
-
-        boolean castedValues = sourceMethod != targetMethod;
-
-        builder.startGroup();
-        ExecutableElement method = targetMethod.getMethod();
-        if (method == null) {
-            throw new UnsupportedOperationException();
-        }
-        TypeElement targetClass = ElementUtils.findNearestEnclosingType(method.getEnclosingElement());
-        NodeData node = (NodeData) targetMethod.getTemplate();
-
-        if (target == null) {
-            boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType());
-            if (accessible) {
-                if (builder.findMethod().getModifiers().contains(STATIC)) {
-                    if (method.getModifiers().contains(STATIC)) {
-                        builder.type(targetClass.asType());
-                    } else {
-                        builder.string(THIS_NODE_LOCAL_VAR_NAME);
-                    }
-                } else {
-                    if (targetMethod instanceof ExecutableTypeData) {
-                        builder.string("this");
-                    } else {
-                        builder.string("super");
-                    }
-                }
-            } else {
-                if (method.getModifiers().contains(STATIC)) {
-                    builder.type(targetClass.asType());
-                } else {
-                    Parameter firstParameter = null;
-                    for (Parameter searchParameter : targetMethod.getParameters()) {
-                        if (searchParameter.getSpecification().isSignature()) {
-                            firstParameter = searchParameter;
-                            break;
-                        }
-                    }
-                    if (firstParameter == null) {
-                        throw new AssertionError();
-                    }
-
-                    Parameter sourceParameter = sourceMethod.findParameter(firstParameter.getLocalName());
-
-                    if (castedValues && sourceParameter != null) {
-                        builder.string(valueName(sourceParameter, firstParameter));
-                    } else {
-                        builder.string(valueName(firstParameter));
-                    }
-                }
-            }
-            builder.string(".");
-        } else {
-            builder.tree(target);
-        }
-        builder.startCall(method.getSimpleName().toString());
-
-        int signatureIndex = 0;
-
-        for (Parameter targetParameter : targetMethod.getParameters()) {
-            Parameter valueParameter = null;
-            if (sourceMethod != null) {
-                valueParameter = sourceMethod.findParameter(targetParameter.getLocalName());
-            }
-            if (valueParameter == null) {
-                valueParameter = targetParameter;
-            }
-            TypeMirror targetType = targetParameter.getType();
-            TypeMirror valueType = null;
-            if (valueParameter != null) {
-                valueType = valueParameter.getType();
-            }
-
-            if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) {
-                builder.string(customSignatureValueNames[signatureIndex]);
-                signatureIndex++;
-            } else if (targetParameter.getSpecification().isLocal()) {
-                builder.startGroup();
-                if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) {
-                    builder.string(THIS_NODE_LOCAL_VAR_NAME).string(".");
-                } else {
-                    builder.string("this.");
-                }
-                builder.string(targetParameter.getSpecification().getName());
-                builder.end();
-            } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) {
-                builder.cast(targetParameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
-            } else if (!ElementUtils.needsCastTo(valueType, targetType)) {
-                builder.startGroup();
-                builder.string(valueName(targetParameter));
-                builder.end();
-            } else {
-                builder.string(castValueName(targetParameter));
-            }
-        }
-
-        builder.end().end();
-
-        return builder.build();
-    }
-
-    public static String baseClassName(NodeData node) {
-        String nodeid = resolveNodeId(node);
-        String name = ElementUtils.firstLetterUpperCase(nodeid);
-        name += "NodeGen";
-        return name;
-    }
-
-    /**
-     * <pre>
-     * variant1 $condition != null
-     *
-     * $type $name = defaultValue($type);
-     * if ($condition) {
-     *     $name = $value;
-     * }
-     *
-     * variant2 $condition != null
-     * $type $name = $value;
-     * </pre>
-     *
-     * .
-     */
-    private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        if (condition == null) {
-            builder.declaration(type, name, value);
-        } else {
-            builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).build());
-
-            builder.startIf().tree(condition).end();
-            builder.startBlock();
-            builder.startStatement();
-            builder.string(name);
-            builder.string(" = ");
-            builder.tree(value);
-            builder.end(); // statement
-            builder.end(); // block
-        }
-        return builder.build();
-    }
-
-    void emitEncounteredSynthetic(CodeTreeBuilder builder, NodeData model, TemplateMethod current) {
-        CodeTreeBuilder nodes = builder.create();
-        CodeTreeBuilder arguments = builder.create();
-        nodes.startCommaGroup();
-        arguments.startCommaGroup();
-        boolean empty = true;
-        for (Parameter parameter : current.getParameters()) {
-            NodeExecutionData executionData = parameter.getSpecification().getExecution();
-            if (executionData != null) {
-                if (executionData.isShortCircuit()) {
-                    nodes.nullLiteral();
-                    arguments.string(valueName(parameter.getPreviousParameter()));
-                }
-                nodes.tree(createAccessChild(executionData, "rootNode"));
-                arguments.string(valueName(parameter));
-                empty = false;
-            }
-        }
-        nodes.end();
-        arguments.end();
-        builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
-
-        builder.declaration(baseClassName(model), "rootNode", builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_FIND_ROOT).string("this").end());
-        builder.startThrow().startNew(context.getType(UnsupportedSpecializationException.class));
-        builder.string("rootNode");
-        builder.startNewArray(context.getTruffleTypes().getNodeArray(), null);
-        builder.tree(nodes.build());
-        builder.end();
-        if (!empty) {
-            builder.tree(arguments.build());
-        }
-        builder.end().end();
-    }
-
-    private static ExecutableElement findCopyConstructor(TypeMirror type) {
-        for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(type).getEnclosedElements())) {
-            if (constructor.getModifiers().contains(PRIVATE)) {
-                continue;
-            }
-            if (isCopyConstructor(constructor)) {
-                return constructor;
-            }
-        }
-
-        return null;
-    }
-
-    static String nodeSpecializationClassName(SpecializationData specialization) {
-        String nodeid = resolveNodeId(specialization.getNode());
-        String name = ElementUtils.firstLetterUpperCase(nodeid);
-        name += ElementUtils.firstLetterUpperCase(specialization.getId());
-        name += "Node";
-        return name;
-    }
-
-    static String nodePolymorphicClassName(NodeData node) {
-        return ElementUtils.firstLetterUpperCase(resolveNodeId(node)) + "PolymorphicNode";
-    }
-
-    private static String resolveNodeId(NodeData node) {
-        String nodeid = node.getNodeId();
-        if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
-            nodeid = nodeid.substring(0, nodeid.length() - 4);
-        }
-        return nodeid;
-    }
-
-    private static CodeTree createCastType(TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) {
-        if (targetType == null) {
-            return value;
-        } else if (sourceType != null && !sourceType.needsCastTo(targetType)) {
-            return value;
-        }
-
-        if (expect) {
-            return TypeSystemCodeGenerator.expect(targetType, value);
-        } else {
-            return TypeSystemCodeGenerator.cast(targetType, value);
-        }
-    }
-
-    private static CodeTree createExpectType(TypeData sourceType, TypeData targetType, CodeTree expression) {
-        return createCastType(sourceType, targetType, true, expression);
-    }
-
-    static CodeTree createDeoptimize(CodeTreeBuilder parent) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        builder.startStatement();
-        builder.startStaticCall(ProcessorContext.getInstance().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end();
-        builder.end();
-        return builder.build();
-    }
-
-    private TypeMirror getUnexpectedValueException() {
-        return context.getTruffleTypes().getUnexpectedValueException();
-    }
-
-    interface CodeBlock<T> {
-
-        CodeTree create(CodeTreeBuilder parent, T value);
-
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Thu Feb 12 04:01:46 2015 +0100
@@ -122,38 +122,14 @@
     }
 
     private static String getAccessorClassName(NodeData node) {
-        return node.isGenerateFactory() ? NodeFactoryFactory.factoryClassName(node) : NodeBaseFactory.baseClassName(node);
+        return node.isGenerateFactory() ? NodeFactoryFactory.factoryClassName(node) : NodeGenFactory.nodeTypeName(node);
     }
 
     private static List<CodeTypeElement> generateNodes(ProcessorContext context, NodeData node) {
         if (!node.needsFactory()) {
             return Collections.emptyList();
         }
-        if (node.getTypeSystem().getOptions().useNewLayout()) {
-            return Arrays.asList(new NodeGenFactory(context, node).create());
-        } else {
-            return generateNodesOld(context, node);
-        }
-    }
-
-    private static List<CodeTypeElement> generateNodesOld(ProcessorContext context, NodeData node) {
-        List<CodeTypeElement> nodeTypes = new ArrayList<>();
-        SpecializationData generic = node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization();
-        CodeTypeElement baseNode = new NodeBaseFactory(context, node, generic).create();
-        nodeTypes.add(baseNode);
-
-        for (SpecializationData specialization : node.getSpecializations()) {
-            if (!specialization.isReachable() || specialization.isFallback()) {
-                continue;
-            }
-            if (specialization.isPolymorphic() && node.isPolymorphic(context)) {
-                nodeTypes.add(new PolymorphicNodeFactory(context, node, specialization, baseNode).create());
-                continue;
-            }
-
-            nodeTypes.add(new SpecializedNodeFactory(context, node, specialization, baseNode).create());
-        }
-        return nodeTypes;
+        return Arrays.asList(new NodeGenFactory(context, node).create());
     }
 
     private static ExecutableElement createGetFactories(ProcessorContext context, NodeData node) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java	Thu Feb 12 04:01:46 2015 +0100
@@ -31,7 +31,6 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.internal.*;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.java.model.*;
@@ -40,20 +39,16 @@
 
 class NodeFactoryFactory {
 
-    static final String FACTORY_METHOD_NAME = "create0";
+    static final String EMPTY_CLASS_ARRAY = "EMPTY_CLASS_ARRAY";
 
     private final ProcessorContext context;
     private final NodeData node;
-    private final TypeSystemData typeSystem;
-    private final DSLOptions options;
     private final CodeTypeElement createdFactoryElement;
 
     public NodeFactoryFactory(ProcessorContext context, NodeData node, CodeTypeElement createdClass) {
         this.context = context;
         this.node = node;
         this.createdFactoryElement = createdClass;
-        this.typeSystem = node.getTypeSystem();
-        this.options = typeSystem.getOptions();
     }
 
     public static String factoryClassName(NodeData node) {
@@ -94,7 +89,7 @@
         // execution signature
         builder.startGroup();
         if (node.getChildExecutions().isEmpty()) {
-            builder.staticReference(context.getTruffleTypes().getDslMetadata(), NodeBaseFactory.EMPTY_CLASS_ARRAY);
+            builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
         } else {
             builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null);
             for (NodeExecutionData execution : node.getChildExecutions()) {
@@ -107,11 +102,11 @@
         // node signatures
         builder.startGroup();
         builder.startNewArray(new ArrayCodeTypeMirror(new ArrayCodeTypeMirror(context.getType(Class.class))), null);
-        List<ExecutableElement> constructors = NodeBaseFactory.findUserConstructors(createdFactoryElement.asType());
+        List<ExecutableElement> constructors = GeneratorUtils.findUserConstructors(createdFactoryElement.asType());
         for (ExecutableElement constructor : constructors) {
             builder.startGroup();
             if (constructor.getParameters().isEmpty()) {
-                builder.staticReference(context.getTruffleTypes().getDslMetadata(), NodeBaseFactory.EMPTY_CLASS_ARRAY);
+                builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
             } else {
                 builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null);
                 for (VariableElement var : constructor.getParameters()) {
@@ -135,7 +130,7 @@
         method.addParameter(arguments);
 
         CodeTreeBuilder builder = method.createBuilder();
-        List<ExecutableElement> signatures = NodeBaseFactory.findUserConstructors(createdFactoryElement.asType());
+        List<ExecutableElement> signatures = GeneratorUtils.findUserConstructors(createdFactoryElement.asType());
         boolean ifStarted = false;
 
         for (ExecutableElement element : signatures) {
@@ -230,7 +225,7 @@
     }
 
     public void createFactoryMethods(CodeTypeElement clazz) {
-        List<ExecutableElement> constructors = NodeBaseFactory.findUserConstructors(createdFactoryElement.asType());
+        List<ExecutableElement> constructors = GeneratorUtils.findUserConstructors(createdFactoryElement.asType());
         for (ExecutableElement constructor : constructors) {
             clazz.add(createCreateMethod(constructor));
             if (constructor instanceof CodeExecutableElement) {
@@ -252,11 +247,7 @@
         if (node.getSpecializations().isEmpty()) {
             body.nullLiteral();
         } else {
-            if (options.useNewLayout()) {
-                body.startNew(NodeGenFactory.nodeType(node));
-            } else {
-                body.startCall(NodeBaseFactory.nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME);
-            }
+            body.startNew(NodeGenFactory.nodeType(node));
             for (VariableElement var : method.getParameters()) {
                 body.string(var.getSimpleName().toString());
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Thu Feb 12 04:01:46 2015 +0100
@@ -32,7 +32,6 @@
 import javax.lang.model.type.*;
 import javax.lang.model.util.*;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.dsl.*;
@@ -42,18 +41,22 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.Node.Child;
+import com.oracle.truffle.api.nodes.Node.Children;
 import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.expression.*;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Variable;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.java.model.*;
+import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
 import com.oracle.truffle.dsl.processor.model.*;
 import com.oracle.truffle.dsl.processor.parser.*;
 import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard;
 
 public class NodeGenFactory {
 
-    private static final String FRAME_VALUE = "frameValue";
-
+    private static final String FRAME_VALUE = TemplateMethod.FRAME_NAME;
     private static final String NAME_SUFFIX = "_";
+    private static final String NODE_SUFFIX = "NodeGen";
 
     private final ProcessorContext context;
     private final NodeData node;
@@ -70,11 +73,10 @@
         this.genericType = typeSystem.getGenericTypeData();
         this.options = typeSystem.getOptions();
         this.singleSpecializable = isSingleSpecializableImpl();
-        this.varArgsThreshold = calculateVarArgsThresHold();
-
+        this.varArgsThreshold = calculateVarArgsThreshold();
     }
 
-    private int calculateVarArgsThresHold() {
+    private int calculateVarArgsThreshold() {
         TypeMirror specialization = context.getType(SpecializationNode.class);
         TypeElement specializationType = fromTypeMirror(specialization);
 
@@ -88,7 +90,11 @@
     }
 
     public static String nodeTypeName(NodeData node) {
-        return resolveNodeId(node) + "NodeGen";
+        return resolveNodeId(node) + NODE_SUFFIX;
+    }
+
+    private static String assumptionName(AssumptionExpression assumption) {
+        return assumption.getId() + NAME_SUFFIX;
     }
 
     private static String resolveNodeId(NodeData node) {
@@ -153,18 +159,10 @@
         }
     }
 
-    private static String assumptionName(String assumption) {
-        return assumption + "_";
-    }
-
     public CodeTypeElement create() {
         CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(FINAL), nodeTypeName(node), node.getTemplateType().asType());
         ElementUtils.setVisibility(clazz.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers()));
 
-        for (String assumption : node.getAssumptions()) {
-            clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getType(Assumption.class), assumptionName(assumption)));
-        }
-
         for (NodeChildData child : node.getChildren()) {
             clazz.addOptional(createAccessChildMethod(child));
         }
@@ -183,7 +181,7 @@
             }
         }
 
-        for (ExecutableElement superConstructor : NodeBaseFactory.findUserConstructors(node.getTemplateType().asType())) {
+        for (ExecutableElement superConstructor : GeneratorUtils.findUserConstructors(node.getTemplateType().asType())) {
             clazz.add(createNodeConstructor(clazz, superConstructor));
         }
 
@@ -240,7 +238,7 @@
 
     private Element createUnsupportedMethod() {
         LocalContext locals = LocalContext.load(this);
-        CodeExecutableElement method = locals.createMethod(modifiers(PRIVATE), getType(UnsupportedSpecializationException.class), "unsupported");
+        CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported");
 
         CodeTreeBuilder builder = method.createBuilder();
         builder.startReturn();
@@ -332,7 +330,7 @@
 
         List<SpecializationData> generateSpecializations = new ArrayList<>();
         generateSpecializations.add(node.getUninitializedSpecialization());
-        if (needsPolymorphic(reachableSpecializations)) {
+        if (needsPolymorphic()) {
             generateSpecializations.add(node.getPolymorphicSpecialization());
         }
         generateSpecializations.addAll(reachableSpecializations);
@@ -348,6 +346,26 @@
         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()) {
+                return true;
+            }
+        }
+        if (specialization.hasMultipleInstances()) {
+            return true;
+        }
+        return false;
+
+    }
+
     // create specialization
 
     private CodeTypeElement createBaseSpecialization() {
@@ -490,7 +508,8 @@
     }
 
     private Element createMergeMethod(SpecializationData specialization) {
-        if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) {
+        boolean cacheBoundGuard = specialization.hasMultipleInstances();
+        if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic() && !cacheBoundGuard) {
             return null;
         }
         TypeMirror specializationNodeType = getType(SpecializationNode.class);
@@ -511,7 +530,11 @@
                 builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")");
                 builder.end();
             }
-            builder.statement("return super.merge(newNode)");
+            if (cacheBoundGuard) {
+                builder.statement("return super.mergeNoSame(newNode)");
+            } else {
+                builder.statement("return super.merge(newNode)");
+            }
         }
 
         return executable;
@@ -553,21 +576,6 @@
         return executable;
     }
 
-    private boolean needsPolymorphic(List<SpecializationData> reachableSpecializations) {
-        if (reachableSpecializations.size() > 1) {
-            return true;
-        }
-        if (options.implicitCastOptimization().isDuplicateTail()) {
-            SpecializationData specialization = reachableSpecializations.get(0);
-            for (Parameter parameter : specialization.getSignatureParameters()) {
-                if (parameter.getTypeSystemType().hasImplicitSourceTypes()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) {
         SpecializationData fallback = node.getGenericSpecialization();
         if (fallback == null) {
@@ -612,7 +620,7 @@
                 if (generatedType == null) {
                     throw new AssertionError("No generated type for " + specialization);
                 }
-                return createSlowPathExecute(specialization, locals);
+                return createSlowPathExecute(specialization, values);
             }
 
             public boolean isFastPath() {
@@ -622,7 +630,7 @@
 
         builder.tree(execution);
 
-        if (hasFallthrough(group, genericType, locals, false)) {
+        if (hasFallthrough(group, genericType, locals, false, null)) {
             builder.returnNull();
         }
         return method;
@@ -711,8 +719,6 @@
         return evaluatedCount;
     }
 
-    // create specialization
-
     private Element createUnsupported() {
         SpecializationData fallback = node.getGenericSpecialization();
         if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) {
@@ -736,12 +742,25 @@
         if (reachableSpecializations.size() != 1) {
             return false;
         }
-        for (Parameter parameter : reachableSpecializations.get(0).getSignatureParameters()) {
+
+        SpecializationData specialization = reachableSpecializations.get(0);
+
+        for (Parameter parameter : specialization.getSignatureParameters()) {
             TypeData type = parameter.getTypeSystemType();
             if (type != null && type.hasImplicitSourceTypes()) {
                 return false;
             }
         }
+
+        if (!specialization.getAssumptionExpressions().isEmpty()) {
+            return false;
+        }
+
+        if (specialization.getCaches().size() > 0) {
+            // TODO chumer: caches do not yet support single specialization.
+            // it could be worthwhile to explore if this is possible
+            return false;
+        }
         return true;
     }
 
@@ -810,7 +829,7 @@
             if (wrappedExecutableType != null) {
                 builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end();
             } else {
-                builder.tree(createFastPathExecute(builder, specialization, execType.getType(), locals));
+                builder.tree(createFastPath(builder, specialization, execType.getType(), locals));
             }
         } else {
             // create acceptAndExecute
@@ -968,7 +987,8 @@
                     continue;
                 }
             }
-            builder.string(parameter.getLocalName());
+
+            builder.defaultValue(parameter.getType());
         }
         builder.end();
         return builder.build();
@@ -1012,9 +1032,46 @@
         if (specialization.isFallback()) {
             return builder.returnNull().build();
         }
+
         if (node.isFrameUsedByAnyGuard()) {
             builder.tree(createTransferToInterpreterAndInvalidate());
         }
+
+        // caches unbound to guards are invoked after all guards
+        for (CacheExpression cache : specialization.getCaches()) {
+            if (!specialization.isCacheBoundByGuard(cache)) {
+                initializeCache(builder, specialization, cache, currentValues);
+            }
+        }
+        boolean hasAssumptions = !specialization.getAssumptionExpressions().isEmpty();
+        if (hasAssumptions) {
+
+            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+                CodeTree assumptions = DSLExpressionGenerator.write(assumption.getExpression(), accessParent(null),
+                                castBoundTypes(bindExpressionValues(assumption.getExpression(), specialization, currentValues)));
+                String name = assumptionName(assumption);
+                // needs specialization index for assumption to make unique
+                String varName = name + specialization.getIndex();
+                TypeMirror type = assumption.getExpression().getResolvedType();
+                builder.declaration(type, varName, assumptions);
+                currentValues.set(name, new LocalVariable(null, type, varName, null));
+            }
+
+            builder.startIf();
+            String sep = "";
+            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+                LocalVariable assumptionVar = currentValues.get(assumptionName(assumption));
+                if (assumptionVar == null) {
+                    throw new AssertionError("assumption var not resolved");
+                }
+                builder.string(sep);
+                builder.startCall("isValid").tree(assumptionVar.createReference()).end();
+                sep = " && ";
+            }
+            builder.end();
+            builder.startBlock();
+        }
+
         for (SpecializationData otherSpeciailzation : node.getSpecializations()) {
             if (otherSpeciailzation == specialization) {
                 continue;
@@ -1027,7 +1084,29 @@
             }
         }
 
-        builder.startReturn().tree(createCallCreateMethod(specialization, null, currentValues)).end();
+        CodeTree create = createCallCreateMethod(specialization, null, currentValues);
+
+        if (specialization.hasMultipleInstances()) {
+            builder.declaration(getType(SpecializationNode.class), "s", create);
+            DSLExpression limitExpression = specialization.getLimitExpression();
+            CodeTree limitExpressionTree;
+            if (limitExpression == null) {
+                limitExpressionTree = CodeTreeBuilder.singleString("3");
+            } else {
+                limitExpressionTree = DSLExpressionGenerator.write(limitExpression, accessParent(null), //
+                                castBoundTypes(bindExpressionValues(limitExpression, specialization, currentValues)));
+            }
+
+            builder.startIf().string("countSame(s) < ").tree(limitExpressionTree).end().startBlock();
+            builder.statement("return s");
+            builder.end();
+        } else {
+            builder.startReturn().tree(create).end();
+        }
+
+        if (hasAssumptions) {
+            builder.end();
+        }
 
         if (mayBeExcluded(specialization)) {
             CodeTreeBuilder checkHasSeenBuilder = builder.create();
@@ -1039,7 +1118,7 @@
         return builder.build();
     }
 
-    private static boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath) {
+    private boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath, List<GuardExpression> ignoreGuards) {
         for (TypeGuard guard : group.getTypeGuards()) {
             if (currentValues.getValue(guard.getSignatureIndex()) == null) {
                 // not evaluated
@@ -1051,22 +1130,44 @@
             }
         }
 
-        List<GuardExpression> expressions = new ArrayList<>(group.getGuards());
-        expressions.removeAll(group.findElseConnectableGuards());
-        if (!expressions.isEmpty()) {
+        List<GuardExpression> guards = new ArrayList<>(group.getGuards());
+        List<GuardExpression> elseConnectable = group.findElseConnectableGuards();
+        guards.removeAll(elseConnectable);
+        if (ignoreGuards != null) {
+            guards.removeAll(ignoreGuards);
+        }
+        SpecializationData specialization = group.getSpecialization();
+        if (specialization != null && fastPath) {
+            for (ListIterator<GuardExpression> iterator = guards.listIterator(); iterator.hasNext();) {
+                GuardExpression guard = iterator.next();
+                if (!specialization.isDynamicParameterBound(guard.getExpression())) {
+                    iterator.remove();
+                }
+            }
+        }
+
+        if (!guards.isEmpty()) {
             return true;
         }
 
-        if ((!fastPath || forType.isGeneric()) && !group.getAssumptions().isEmpty()) {
+        if (!fastPath && specialization != null && !specialization.getAssumptionExpressions().isEmpty()) {
+            return true;
+        }
+
+        if (!fastPath && specialization != null && mayBeExcluded(specialization)) {
             return true;
         }
 
-        if (!fastPath && group.getSpecialization() != null && !group.getSpecialization().getExceptions().isEmpty()) {
-            return true;
+        if (!elseConnectable.isEmpty()) {
+            SpecializationGroup previous = group.getPrevious();
+            if (previous != null && hasFallthrough(previous, forType, currentValues, fastPath, previous.getGuards())) {
+                return true;
+            }
         }
 
-        if (!group.getChildren().isEmpty()) {
-            return hasFallthrough(group.getChildren().get(group.getChildren().size() - 1), forType, currentValues, fastPath);
+        List<SpecializationGroup> groupChildren = group.getChildren();
+        if (!groupChildren.isEmpty()) {
+            return hasFallthrough(groupChildren.get(groupChildren.size() - 1), forType, currentValues, fastPath, ignoreGuards);
         }
 
         return false;
@@ -1117,11 +1218,25 @@
         }
         if (currentValues != null) {
             for (Parameter p : specialization.getSignatureParameters()) {
-                LocalVariable local = currentValues.get(p.getLocalName());
                 CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType());
                 if (var != null) {
-                    builder.tree(local.createReference());
+                    // we need the original name here
+                    builder.tree(LocalVariable.fromParameter(p).createReference());
+                }
+            }
+            for (CacheExpression cache : specialization.getCaches()) {
+                LocalVariable variable = currentValues.get(cache.getParameter().getLocalName());
+                if (variable == null) {
+                    throw new AssertionError("Could not bind cached value " + cache.getParameter().getLocalName() + ": " + currentValues);
                 }
+                builder.tree(variable.createReference());
+            }
+            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+                LocalVariable variable = currentValues.get(assumptionName(assumption));
+                if (variable == null) {
+                    throw new AssertionError("Could not bind assumption value " + assumption.getId() + ": " + currentValues);
+                }
+                builder.tree(variable.createReference());
             }
         }
         builder.end();
@@ -1199,6 +1314,31 @@
                     }
                 }
             }
+            for (CacheExpression cache : specialization.getCaches()) {
+                String name = cache.getParameter().getLocalName();
+                TypeMirror type = cache.getParameter().getType();
+
+                if (ElementUtils.isAssignable(type, new ArrayCodeTypeMirror(getType(Node.class)))) {
+                    CodeVariableElement var = clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name));
+                    var.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(Children.class)));
+                } else if (ElementUtils.isAssignable(type, getType(Node.class))) {
+                    CodeVariableElement var = clazz.add(new CodeVariableElement(modifiers(PRIVATE), type, name));
+                    var.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(Child.class)));
+                } else {
+                    clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name));
+                }
+                constructor.addParameter(new CodeVariableElement(type, name));
+                builder.startStatement().string("this.").string(name).string(" = ").string(name).end();
+            }
+
+            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+                String name = assumptionName(assumption);
+                TypeMirror type = assumption.getExpression().getResolvedType();
+                CodeVariableElement field = clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name));
+                field.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(CompilationFinal.class)));
+                constructor.addParameter(new CodeVariableElement(type, name));
+                builder.startStatement().string("this.").string(name).string(" = ").string(name).end();
+            }
         }
 
         if (constructor.getParameters().isEmpty()) {
@@ -1258,9 +1398,12 @@
         return builder.build();
     }
 
-    private static CodeTree createCallDelegate(String methodName, TypeData forType, LocalContext currentValues) {
+    private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) {
         CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
         builder.startCall(methodName);
+        if (reason != null) {
+            builder.doubleQuote(reason);
+        }
         currentValues.addReferencesTo(builder, FRAME_VALUE);
         builder.end();
 
@@ -1300,6 +1443,10 @@
         TypeData type = forType == null ? genericType : forType;
         LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold);
 
+        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)));
 
@@ -1308,12 +1455,12 @@
         }
 
         CodeTreeBuilder builder = executable.createBuilder();
-        builder.tree(createFastPathExecute(builder, specialization, type, currentLocals));
+        builder.tree(createFastPath(builder, specialization, type, currentLocals));
 
         return executable;
     }
 
-    private CodeTree createFastPathExecute(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) {
+    private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) {
         final CodeTreeBuilder builder = parent.create();
 
         for (NodeExecutionData execution : node.getChildExecutions()) {
@@ -1334,11 +1481,11 @@
 
         LocalContext originalValues = currentLocals.copy();
         if (specialization == null) {
-            builder.startReturn().tree(createCallDelegate("acceptAndExecute", type, currentLocals)).end();
+            builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end();
         } else if (specialization.isPolymorphic()) {
             builder.tree(createCallNext(type, currentLocals));
         } else if (specialization.isUninitialized()) {
-            builder.startReturn().tree(createCallDelegate("uninitialized", type, currentLocals)).end();
+            builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end();
         } else {
             final TypeData finalType = type;
             SpecializationGroup group = SpecializationGroup.create(specialization);
@@ -1352,7 +1499,7 @@
                 }
             };
             builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory));
-            if (hasFallthrough(group, type, originalValues, true) || group.getSpecialization().isFallback()) {
+            if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) {
                 builder.tree(createCallNext(type, originalValues));
             }
         }
@@ -1403,6 +1550,27 @@
             ifCount++;
         }
         CodeTreeBuilder execute = builder.create();
+
+        if (!specialization.getAssumptionExpressions().isEmpty()) {
+            builder.startTryBlock();
+            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+                LocalVariable assumptionVar = currentValues.get(assumptionName(assumption));
+                if (assumptionVar == null) {
+                    throw new AssertionError("Could not resolve assumption var " + currentValues);
+                }
+                builder.startStatement().startCall("check").tree(assumptionVar.createReference()).end().end();
+            }
+            builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae");
+            builder.startReturn();
+            List<String> assumptionIds = new ArrayList<>();
+            for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
+                assumptionIds.add(assumption.getId());
+            }
+            builder.tree(createCallDelegate("removeThis", String.format("Assumption %s invalidated", assumptionIds), forType, currentValues));
+            builder.end();
+            builder.end();
+        }
+
         execute.startReturn();
         if (specialization.getMethod() == null) {
             execute.startCall("unsupported");
@@ -1426,27 +1594,24 @@
         } else {
             castGuards = new HashSet<>();
             for (TypeGuard castGuard : group.getTypeGuards()) {
-                if (isTypeGuardUsedInAnyGuardBelow(group, currentValues, castGuard)) {
+                if (isTypeGuardUsedInAnyGuardOrCacheBelow(group, currentValues, castGuard)) {
                     castGuards.add(castGuard);
                 }
             }
         }
-        CodeTree[] checkAndCast = createTypeCheckAndCast(group.getTypeGuards(), castGuards, currentValues, execution);
+
+        SpecializationData specialization = group.getSpecialization();
+        CodeTree[] checkAndCast = createTypeCheckAndLocals(specialization, group.getTypeGuards(), castGuards, currentValues, execution);
+
         CodeTree check = checkAndCast[0];
         CodeTree cast = checkAndCast[1];
 
         List<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards();
         List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards());
         guardExpressions.removeAll(elseGuardExpressions);
-        CodeTree methodGuards = createMethodGuardCheck(guardExpressions, currentValues);
-
-        if (!group.getAssumptions().isEmpty()) {
-            if (execution.isFastPath() && !forType.isGeneric()) {
-                cast = appendAssumptionFastPath(cast, group.getAssumptions(), forType, currentValues);
-            } else {
-                methodGuards = appendAssumptionSlowPath(methodGuards, group.getAssumptions());
-            }
-        }
+        CodeTree[] methodGuardAndAssertions = createMethodGuardCheck(guardExpressions, specialization, currentValues, execution.isFastPath());
+        CodeTree methodGuards = methodGuardAndAssertions[0];
+        CodeTree guardAssertions = methodGuardAndAssertions[1];
 
         int ifCount = 0;
         if (!check.isEmpty()) {
@@ -1468,13 +1633,15 @@
             builder.startElseBlock();
             ifCount++;
         }
+        if (!guardAssertions.isEmpty()) {
+            builder.tree(guardAssertions);
+        }
 
         boolean reachable = isReachableGroup(group, ifCount);
         if (reachable) {
             for (SpecializationGroup child : group.getChildren()) {
                 builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution));
             }
-            SpecializationData specialization = group.getSpecialization();
             if (specialization != null) {
                 builder.tree(execution.createExecute(specialization, currentValues));
             }
@@ -1484,33 +1651,6 @@
         return builder.build();
     }
 
-    private CodeTree appendAssumptionSlowPath(CodeTree methodGuards, List<String> assumptions) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-
-        builder.tree(methodGuards);
-        String connect = methodGuards.isEmpty() ? "" : " && ";
-        for (String assumption : assumptions) {
-            builder.string(connect);
-            builder.startCall(accessParent(assumptionName(assumption)), "isValid").end();
-            connect = " && ";
-        }
-
-        return builder.build();
-    }
-
-    private CodeTree appendAssumptionFastPath(CodeTree casts, List<String> assumptions, TypeData forType, LocalContext currentValues) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
-        builder.tree(casts);
-        builder.startTryBlock();
-        for (String assumption : assumptions) {
-            builder.startStatement().startCall(accessParent(assumptionName(assumption)), "check").end().end();
-        }
-        builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae");
-        builder.tree(createCallNext(forType, currentValues));
-        builder.end();
-        return builder.build();
-    }
-
     private static boolean isReachableGroup(SpecializationGroup group, int ifCount) {
         if (ifCount != 0) {
             return true;
@@ -1524,7 +1664,7 @@
          * Hacky else case. In this case the specialization is not reachable due to previous else
          * branch. This is only true if the minimum state is not checked.
          */
-        if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() &&
+        if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() &&
                         (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) {
             return false;
         }
@@ -1532,22 +1672,25 @@
         return true;
     }
 
-    private boolean isTypeGuardUsedInAnyGuardBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) {
-        NodeExecutionData execution = node.getChildExecutions().get(typeGuard.getSignatureIndex());
+    private boolean isTypeGuardUsedInAnyGuardOrCacheBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) {
+        String localName = currentValues.getValue(typeGuard.getSignatureIndex()).getName();
 
+        SpecializationData specialization = group.getSpecialization();
         for (GuardExpression guard : group.getGuards()) {
-            List<Parameter> guardParameters = guard.getResolvedGuard().findByExecutionData(execution);
-            TypeData sourceType = currentValues.getValue(typeGuard.getSignatureIndex()).getType();
-
-            for (Parameter guardParameter : guardParameters) {
-                if (sourceType.needsCastTo(guardParameter.getType())) {
+            if (isVariableBoundIn(specialization, guard.getExpression(), localName, currentValues)) {
+                return true;
+            }
+        }
+        if (specialization != null) {
+            for (CacheExpression cache : specialization.getCaches()) {
+                if (isVariableBoundIn(specialization, cache.getExpression(), localName, currentValues)) {
                     return true;
                 }
             }
         }
 
         for (SpecializationGroup child : group.getChildren()) {
-            if (isTypeGuardUsedInAnyGuardBelow(child, currentValues, typeGuard)) {
+            if (isTypeGuardUsedInAnyGuardOrCacheBelow(child, currentValues, typeGuard)) {
                 return true;
             }
         }
@@ -1555,6 +1698,17 @@
         return false;
     }
 
+    private static boolean isVariableBoundIn(SpecializationData specialization, DSLExpression expression, String localName, LocalContext currentValues) throws AssertionError {
+        Map<Variable, LocalVariable> boundValues = bindExpressionValues(expression, specialization, currentValues);
+        for (Variable var : expression.findBoundVariables()) {
+            LocalVariable target = boundValues.get(var);
+            if (target != null && localName.equals(target.getName())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) {
         LocalContext locals = LocalContext.load(this, 0, varArgsThreshold);
 
@@ -1946,23 +2100,80 @@
         return builder.build();
     }
 
-    private CodeTree createMethodGuardCheck(List<GuardExpression> guardExpressions, LocalContext currentValues) {
-        CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
+    private CodeTree[] createMethodGuardCheck(List<GuardExpression> guardExpressions, SpecializationData specialization, LocalContext currentValues, boolean fastPath) {
+        CodeTreeBuilder expressionBuilder = CodeTreeBuilder.createBuilder();
+        CodeTreeBuilder assertionBuilder = CodeTreeBuilder.createBuilder();
         String and = "";
         for (GuardExpression guard : guardExpressions) {
-            builder.string(and);
-            if (guard.isNegated()) {
-                builder.string("!");
+            DSLExpression expression = guard.getExpression();
+
+            Map<Variable, CodeTree> resolvedBindings = castBoundTypes(bindExpressionValues(expression, specialization, currentValues));
+            CodeTree expressionCode = DSLExpressionGenerator.write(expression, accessParent(null), resolvedBindings);
+
+            if (!specialization.isDynamicParameterBound(expression) && fastPath) {
+                /*
+                 * Guards where no dynamic parameters are bound can just be executed on the fast
+                 * path.
+                 */
+                assertionBuilder.startAssert().tree(expressionCode).end();
+            } else {
+                expressionBuilder.string(and);
+                expressionBuilder.tree(expressionCode);
+                and = " && ";
             }
-            builder.tree(callTemplateMethod(accessParent(null), guard.getResolvedGuard(), currentValues));
-            and = " && ";
         }
-        return builder.build();
+        return new CodeTree[]{expressionBuilder.build(), assertionBuilder.build()};
     }
 
-    private CodeTree[] createTypeCheckAndCast(List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) {
+    private static Map<Variable, CodeTree> castBoundTypes(Map<Variable, LocalVariable> bindings) {
+        Map<Variable, CodeTree> resolvedBindings = new HashMap<>();
+        for (Variable variable : bindings.keySet()) {
+            LocalVariable localVariable = bindings.get(variable);
+            CodeTree resolved = localVariable.createReference();
+            TypeMirror sourceType = localVariable.getTypeMirror();
+            TypeMirror targetType = variable.getResolvedTargetType();
+            if (targetType == null) {
+                targetType = variable.getResolvedType();
+            }
+            if (!ElementUtils.isAssignable(sourceType, targetType)) {
+                resolved = CodeTreeBuilder.createBuilder().cast(targetType, resolved).build();
+            }
+            resolvedBindings.put(variable, resolved);
+        }
+        return resolvedBindings;
+    }
+
+    private static Map<Variable, LocalVariable> bindExpressionValues(DSLExpression expression, SpecializationData specialization, LocalContext currentValues) throws AssertionError {
+        Map<Variable, LocalVariable> bindings = new HashMap<>();
+
+        Set<Variable> boundVariables = expression.findBoundVariables();
+        if (specialization == null && !boundVariables.isEmpty()) {
+            throw new AssertionError("Cannot bind guard variable in non-specialization group. yet.");
+        }
+
+        // resolve bindings for local context
+        for (Variable variable : boundVariables) {
+            Parameter resolvedParameter = specialization.findByVariable(variable.getResolvedVariable());
+            if (resolvedParameter != null) {
+                LocalVariable localVariable;
+                if (resolvedParameter.getSpecification().isSignature()) {
+                    NodeExecutionData execution = resolvedParameter.getSpecification().getExecution();
+                    localVariable = currentValues.getValue(execution);
+                } else {
+                    localVariable = currentValues.get(resolvedParameter.getLocalName());
+                }
+                if (localVariable != null) {
+                    bindings.put(variable, localVariable);
+                }
+            }
+        }
+        return bindings;
+    }
+
+    private CodeTree[] createTypeCheckAndLocals(SpecializationData specialization, List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues,
+                    SpecializationExecution specializationExecution) {
         CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder();
-        CodeTreeBuilder castsBuilder = CodeTreeBuilder.createBuilder();
+        CodeTreeBuilder localsBuilder = CodeTreeBuilder.createBuilder();
         for (TypeGuard typeGuard : typeGuards) {
             int signatureIndex = typeGuard.getSignatureIndex();
             LocalVariable value = currentValues.getValue(signatureIndex);
@@ -2023,12 +2234,31 @@
             if (castGuards == null || castGuards.contains(typeGuard)) {
                 LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null);
                 currentValues.setValue(execution, castVariable);
-                castsBuilder.tree(castVariable.createDeclaration(castBuilder.build()));
+                localsBuilder.tree(castVariable.createDeclaration(castBuilder.build()));
             }
 
             checksBuilder.tree(checkBuilder.build());
         }
-        return new CodeTree[]{checksBuilder.build(), castsBuilder.build()};
+
+        if (specialization != null && !specializationExecution.isFastPath()) {
+            for (CacheExpression cache : specialization.getCaches()) {
+                if (specialization.isCacheBoundByGuard(cache)) {
+                    initializeCache(localsBuilder, specialization, cache, currentValues);
+                }
+            }
+        }
+
+        return new CodeTree[]{checksBuilder.build(), localsBuilder.build()};
+    }
+
+    private void initializeCache(CodeTreeBuilder builder, SpecializationData specialization, CacheExpression cache, LocalContext currentValues) {
+        CodeTree initializer = DSLExpressionGenerator.write(cache.getExpression(), accessParent(null), castBoundTypes(bindExpressionValues(cache.getExpression(), specialization, currentValues)));
+        String name = cache.getParameter().getLocalName();
+        // multiple specializations might use the same name
+        String varName = name + specialization.getIndex();
+        TypeMirror type = cache.getParameter().getType();
+        builder.declaration(type, varName, initializer);
+        currentValues.set(name, new LocalVariable(null, type, varName, null));
     }
 
     public static final class LocalContext {
@@ -2040,6 +2270,20 @@
             this.factory = factory;
         }
 
+        public void loadFastPathState(SpecializationData specialization) {
+            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)));
+            }
+
+            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)));
+            }
+        }
+
         public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) {
             CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name);
             addParametersTo(method, optionalArguments);
@@ -2238,6 +2482,11 @@
             return values.get(shortCircuitName(execution));
         }
 
+        @Override
+        public String toString() {
+            return "LocalContext [values=" + values + "]";
+        }
+
     }
 
     public static final class LocalVariable {
@@ -2329,6 +2578,11 @@
             return newType(type.getTypeSystem().getGenericTypeData());
         }
 
+        @Override
+        public String toString() {
+            return "Local[type = " + getTypeMirror() + ", name = " + name + ", accessWith = " + accessorTree + "]";
+        }
+
     }
 
     private interface SpecializationExecution {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java	Thu Feb 12 03:42:51 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +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 java.util.*;
-
-import javax.lang.model.type.*;
-
-import com.oracle.truffle.api.nodes.*;
-import com.oracle.truffle.dsl.processor.*;
-import com.oracle.truffle.dsl.processor.java.model.*;
-import com.oracle.truffle.dsl.processor.model.*;
-
-class PolymorphicNodeFactory extends SpecializedNodeFactory {
-
-    public PolymorphicNodeFactory(ProcessorContext context, NodeData node, SpecializationData specialization, CodeTypeElement nodeGen) {
-        super(context, node, specialization, nodeGen);
-    }
-
-    @Override
-    public CodeTypeElement create() {
-        TypeMirror baseType = node.getNodeType();
-        if (nodeGen != null) {
-            baseType = nodeGen.asType();
-        }
-        CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, FINAL), nodePolymorphicClassName(node), baseType);
-
-        clazz.getAnnotationMirrors().add(createNodeInfo(NodeCost.POLYMORPHIC));
-
-        for (Parameter polymorphParameter : specialization.getSignatureParameters()) {
-            if (!polymorphParameter.getTypeSystemType().isGeneric()) {
-                continue;
-            }
-            Set<TypeData> types = new HashSet<>();
-            for (SpecializationData otherSpecialization : node.getSpecializations()) {
-                if (!otherSpecialization.isSpecialized()) {
-                    continue;
-                }
-                Parameter parameter = otherSpecialization.findParameter(polymorphParameter.getLocalName());
-                assert parameter != null;
-                types.add(parameter.getTypeSystemType());
-            }
-
-        }
-
-        for (NodeExecutionData execution : node.getChildExecutions()) {
-            String fieldName = polymorphicTypeName(execution);
-            CodeVariableElement var = new CodeVariableElement(modifiers(PRIVATE), context.getType(Class.class), fieldName);
-            var.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getTruffleTypes().getCompilationFinal()));
-            clazz.add(var);
-        }
-
-        createConstructors(clazz);
-        createExecuteMethods(clazz);
-
-        clazz.add(createUpdateTypes0());
-        createCachedExecuteMethods(clazz);
-
-        return clazz;
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java	Thu Feb 12 03:42:51 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,557 +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 java.util.*;
-
-import javax.lang.model.element.*;
-import javax.lang.model.type.*;
-import javax.lang.model.util.*;
-
-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.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
-import com.oracle.truffle.dsl.processor.model.*;
-import com.oracle.truffle.dsl.processor.parser.*;
-
-class SpecializedNodeFactory extends NodeBaseFactory {
-
-    protected final CodeTypeElement nodeGen;
-
-    public SpecializedNodeFactory(ProcessorContext context, NodeData node, SpecializationData specialization, CodeTypeElement nodeGen) {
-        super(context, node, specialization);
-        this.nodeGen = nodeGen;
-    }
-
-    @Override
-    public CodeTypeElement create() {
-        TypeMirror baseType = node.getNodeType();
-        if (nodeGen != null) {
-            baseType = nodeGen.asType();
-        }
-        CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, FINAL), nodeSpecializationClassName(specialization), baseType);
-
-        if (specialization.isSpecialized() || specialization.isUninitialized()) {
-            clazz.add(createGetMetadata0(false));
-            clazz.add(createMetadataLiteral());
-        }
-
-        NodeCost cost;
-        if (specialization.isFallback()) {
-            cost = NodeCost.MEGAMORPHIC;
-        } else if (specialization.isUninitialized()) {
-            cost = NodeCost.UNINITIALIZED;
-        } else if (specialization.isPolymorphic()) {
-            cost = NodeCost.POLYMORPHIC;
-        } else if (specialization.isSpecialized()) {
-            cost = NodeCost.MONOMORPHIC;
-        } else {
-            throw new AssertionError();
-        }
-        clazz.getAnnotationMirrors().add(createNodeInfo(cost));
-
-        if (specialization.isUninitialized() && node.getGenericSpecialization().isReachable()) {
-            clazz.add(createUninitializedGetCostOverride());
-        }
-
-        createConstructors(clazz);
-
-        createExecuteMethods(clazz);
-        createCachedExecuteMethods(clazz);
-
-        if (specialization.isUninitialized()) {
-            if (specialization.getNode().isFallbackReachable()) {
-                CodeVariableElement var = new CodeVariableElement(modifiers(Modifier.PRIVATE), context.getType(boolean.class), CONTAINS_FALLBACK);
-                var.addAnnotationMirror(new CodeAnnotationMirror(context.getTruffleTypes().getCompilationFinal()));
-                clazz.add(var);
-            }
-            clazz.add(createExecuteUninitialized());
-        }
-
-        if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) {
-            clazz.add(createCopyConstructorFactoryMethod(clazz, nodeGen.asType()));
-        } else {
-            for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
-                if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) {
-                    // skip copy constructor - not used
-                    continue;
-                }
-                clazz.add(createConstructorFactoryMethod(clazz, constructor));
-            }
-        }
-
-        return clazz;
-    }
-
-    private Element createUninitializedGetCostOverride() {
-        TypeMirror returnType = context.getTruffleTypes().getNodeCost();
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost");
-        CodeTreeBuilder builder = method.createBuilder();
-        builder.startIf().string(CONTAINS_FALLBACK).end().startBlock();
-        builder.startReturn().staticReference(returnType, "MONOMORPHIC").end();
-        builder.end();
-        builder.startReturn().string("super.getCost()").end();
-        return method;
-    }
-
-    private CodeVariableElement createMetadataLiteral() {
-        CodeVariableElement includes = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getTruffleTypes().getDslMetadata(), METADATA_FIELD_NAME);
-
-        CodeTreeBuilder builder = includes.createInitBuilder();
-
-        Set<SpecializationData> contains = specialization.getContains();
-        if (specialization.isUninitialized()) {
-            contains = new HashSet<>();
-
-            SpecializationData polymorphic = node.getPolymorphicSpecialization();
-            if (polymorphic != null) {
-                contains.addAll(polymorphic.getContains());
-            }
-            SpecializationData generic = node.getGenericSpecialization();
-            if (generic != null) {
-                contains.addAll(generic.getContains());
-            }
-        }
-
-        builder.startNew(context.getTruffleTypes().getDslMetadata());
-        builder.startGroup().string(nodeSpecializationClassName(getSpecialization()), ".class").end();
-        builder.tree(createSpecializationListLiteral(builder, contains));
-        builder.tree(createSpecializationListLiteral(builder, getSpecialization().getExcludedBy()));
-        builder.tree(createSpecializationTypeLiteral(builder, SpecializationData.getSignatureTypes(getSpecialization())));
-        builder.string("0").string("0");
-        builder.end();
-        return includes;
-    }
-
-    private CodeTree createSpecializationTypeLiteral(CodeTreeBuilder parent, List<TypeMirror> list) {
-        ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
-        CodeTreeBuilder builder = parent.create();
-
-        if (list.isEmpty()) {
-            builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
-        } else {
-            builder.startNewArray(classArray, null);
-            for (TypeMirror type : list) {
-                builder.typeLiteral(type);
-            }
-            builder.end();
-        }
-
-        return builder.build();
-    }
-
-    private CodeTree createSpecializationListLiteral(CodeTreeBuilder parent, Set<SpecializationData> list) {
-        ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
-        CodeTreeBuilder builder = parent.create();
-
-        if (list.isEmpty()) {
-            builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
-        } else {
-            builder.startNewArray(classArray, null);
-            for (SpecializationData current : list) {
-                SpecializationData s = current;
-                if (s.isFallback() || s.isPolymorphic()) {
-                    s = getSpecialization().getNode().getUninitializedSpecialization();
-                }
-                builder.startGroup().string(nodeSpecializationClassName(s)).string(".class").end();
-            }
-            builder.end();
-        }
-
-        return builder.build();
-    }
-
-    protected CodeAnnotationMirror createNodeInfo(NodeCost cost) {
-        String shortName = node.getShortName();
-        CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(context.getTruffleTypes().getNodeInfoAnnotation());
-        if (shortName != null) {
-            nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName));
-        }
-
-        DeclaredType nodeinfoCost = context.getTruffleTypes().getNodeCost();
-        VariableElement varKind = ElementUtils.findVariableElement(nodeinfoCost, cost.name());
-
-        nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("cost"), new CodeAnnotationValue(varKind));
-        return nodeInfoMirror;
-    }
-
-    protected void createConstructors(CodeTypeElement clazz) {
-        TypeElement superTypeElement = ElementUtils.fromTypeMirror(clazz.getSuperclass());
-        for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) {
-            if (specialization.isUninitialized()) {
-                // ignore copy constructors for uninitialized if not polymorphic
-                if (isCopyConstructor(constructor) && !node.isPolymorphic(context)) {
-                    continue;
-                }
-            } else if (node.getUninitializedSpecialization() != null) {
-                // ignore others than copy constructors for specialized nodes
-                if (!isCopyConstructor(constructor)) {
-                    continue;
-                }
-            }
-
-            CodeExecutableElement superConstructor = GeneratorUtils.createSuperConstructor(context, clazz, constructor);
-            if (superConstructor == null) {
-                continue;
-            }
-            CodeTree body = superConstructor.getBodyTree();
-            CodeTreeBuilder builder = superConstructor.createBuilder();
-            builder.tree(body);
-
-            if (superConstructor != null) {
-                for (Parameter param : getImplicitTypeParameters(getSpecialization())) {
-                    clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), context.getType(Class.class), implicitTypeName(param)));
-                    superConstructor.getParameters().add(new CodeVariableElement(context.getType(Class.class), implicitTypeName(param)));
-
-                    builder.startStatement();
-                    builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param));
-                    builder.end();
-                }
-
-                clazz.add(superConstructor);
-            }
-        }
-    }
-
-    protected void createExecuteMethods(CodeTypeElement clazz) {
-
-        List<ExecutableTypeData> primaryExecutes = null;
-        int lastEvaluatedCount = -1;
-
-        for (ExecutableTypeData execType : node.getExecutableTypes()) {
-            if (execType.isFinal()) {
-                continue;
-            }
-            if (execType.getEvaluatedCount() != lastEvaluatedCount) {
-                lastEvaluatedCount = execType.getEvaluatedCount();
-                primaryExecutes = findFunctionalExecutableType(lastEvaluatedCount);
-            }
-
-            CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true);
-            clazz.add(executeMethod);
-            CodeTreeBuilder builder = executeMethod.getBuilder();
-            CodeTree result = createExecuteBody(builder, execType, primaryExecutes);
-            if (result != null) {
-                builder.tree(result);
-            } else {
-                clazz.remove(executeMethod);
-            }
-        }
-    }
-
-    protected void createCachedExecuteMethods(CodeTypeElement clazz) {
-        if (!node.isPolymorphic(context)) {
-            return;
-        }
-
-        final SpecializationData polymorphic = node.getPolymorphicSpecialization();
-        ExecutableElement executeCached = nodeGen.getMethod(EXECUTE_CHAINED);
-        CodeExecutableElement executeMethod = CodeExecutableElement.clone(context.getEnvironment(), executeCached);
-        executeMethod.getModifiers().remove(Modifier.ABSTRACT);
-        CodeTreeBuilder builder = executeMethod.createBuilder();
-
-        if (specialization.isPolymorphic()) {
-            builder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
-            addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, false, null);
-            builder.end().end();
-        } else if (specialization.isUninitialized()) {
-            builder.tree(createDeoptimizeUninitialized(node, builder));
-            builder.startReturn().startCall("this", EXECUTE_UNINITIALIZED);
-            addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, false, null);
-            builder.end().end();
-        } else {
-            CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
-            elseBuilder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
-            addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, false, null);
-            elseBuilder.end().end();
-
-            builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
-
-                public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
-                    return createGenericInvoke(b, polymorphic, current);
-                }
-            }, elseBuilder.build(), false, true, true, false));
-        }
-        clazz.add(executeMethod);
-    }
-
-    private static CodeTree createDeoptimizeUninitialized(NodeData node, CodeTreeBuilder parent) {
-        CodeTreeBuilder builder = parent.create();
-        if (node.getGenericSpecialization().isReachable()) {
-            builder.startIf().string("!containsFallback").end().startBlock();
-            builder.tree(createDeoptimize(builder));
-            builder.end();
-        } else {
-            builder.tree(createDeoptimize(builder));
-        }
-        return builder.build();
-    }
-
-    private CodeTree createExecuteBody(CodeTreeBuilder parent, ExecutableTypeData execType, List<ExecutableTypeData> primaryExecutes) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) {
-            builder.tree(createFunctionalExecute(builder, execType));
-        } else if (needsCastingExecuteMethod(execType)) {
-            assert !primaryExecutes.isEmpty();
-            builder.tree(createCastingExecute(builder, execType, primaryExecutes.get(0)));
-        } else {
-            return null;
-        }
-
-        return builder.build();
-    }
-
-    private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) {
-        CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod());
-
-        method.getAnnotationMirrors().clear();
-        for (VariableElement variable : method.getParameters()) {
-            variable.getAnnotationMirrors().clear();
-        }
-
-        CodeTreeBuilder builder = method.createBuilder();
-        int i = 0;
-        int signatureIndex = -1;
-        for (VariableElement param : method.getParameters()) {
-            CodeVariableElement var = CodeVariableElement.clone(param);
-            Parameter actualParameter = i < execType.getParameters().size() ? execType.getParameters().get(i) : null;
-            String name;
-            if (actualParameter != null) {
-                if (actualParameter.getSpecification().isSignature()) {
-                    signatureIndex++;
-                }
-
-                if (evaluated && actualParameter.getSpecification().isSignature()) {
-                    name = valueNameEvaluated(actualParameter);
-                } else {
-                    name = valueName(actualParameter);
-                }
-
-                int varArgCount = getSpecialization().getSignatureSize() - signatureIndex;
-                if (evaluated && actualParameter.isTypeVarArgs()) {
-                    Parameter baseVarArgs = actualParameter;
-                    name = valueName(baseVarArgs) + "Args";
-
-                    builder.startAssert().string(name).string(" != null").end();
-                    builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end();
-                    if (varArgCount > 0) {
-                        List<Parameter> varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size());
-                        for (Parameter varArg : varArgsParameter) {
-                            if (varArgCount <= 0) {
-                                break;
-                            }
-                            TypeMirror type = baseVarArgs.getType();
-                            if (type.getKind() == TypeKind.ARRAY) {
-                                type = ((ArrayType) type).getComponentType();
-                            }
-                            builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getTypeVarArgsIndex() + "]");
-                            varArgCount--;
-                        }
-                    }
-                }
-            } else {
-                name = "arg" + i;
-            }
-            var.setName(name);
-            method.getParameters().set(i, var);
-            i++;
-        }
-
-        method.getAnnotationMirrors().clear();
-        method.getModifiers().remove(Modifier.ABSTRACT);
-        return method;
-    }
-
-    private static boolean needsCastingExecuteMethod(ExecutableTypeData execType) {
-        if (execType.isAbstract()) {
-            return true;
-        }
-        if (execType.getType().isGeneric()) {
-            return true;
-        }
-        return false;
-    }
-
-    private List<ExecutableTypeData> findFunctionalExecutableType(int evaluatedCount) {
-        TypeData primaryType = specialization.getReturnType().getTypeSystemType();
-        List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount);
-
-        List<ExecutableTypeData> filteredTypes = new ArrayList<>();
-        for (ExecutableTypeData compareType : otherTypes) {
-            if (ElementUtils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) {
-                filteredTypes.add(compareType);
-            }
-        }
-
-        // no direct matches found use generic where the type is Object
-        if (filteredTypes.isEmpty()) {
-            for (ExecutableTypeData compareType : otherTypes) {
-                if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(context)) {
-                    filteredTypes.add(compareType);
-                }
-            }
-        }
-
-        if (filteredTypes.isEmpty()) {
-            for (ExecutableTypeData compareType : otherTypes) {
-                if (compareType.getType().isGeneric()) {
-                    filteredTypes.add(compareType);
-                }
-            }
-        }
-
-        return filteredTypes;
-    }
-
-    private CodeTree createFunctionalExecute(CodeTreeBuilder parent, final ExecutableTypeData executable) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-
-        if (specialization.isUninitialized()) {
-            builder.tree(createDeoptimizeUninitialized(specialization.getNode(), builder));
-        }
-
-        builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null));
-
-        CodeTree returnSpecialized = null;
-
-        if (specialization.findNextSpecialization() != null) {
-            CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder);
-            returnBuilder.tree(createDeoptimize(builder));
-            returnBuilder.tree(createCallRewriteMonomorphic(builder, executable.hasUnexpectedValue(context), executable.getType(), null, "One of guards " + specialization.getGuards() + " failed"));
-            returnSpecialized = returnBuilder.build();
-        }
-
-        builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
-
-            public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
-                return createExecute(b, executable);
-            }
-        }, returnSpecialized, false, false, false, false));
-
-        return builder.build();
-    }
-
-    private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable) {
-        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-        if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) {
-            builder.startTryBlock();
-        }
-
-        for (String assumption : specialization.getAssumptions()) {
-            builder.startStatement();
-            builder.string("this.").string(assumption).string(".check()");
-            builder.end();
-        }
-
-        CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
-        if (specialization.isPolymorphic()) {
-            returnBuilder.startCall("next0", EXECUTE_CHAINED);
-            addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, false, null);
-            returnBuilder.end();
-        } else if (specialization.isUninitialized()) {
-            returnBuilder.startCall(EXECUTE_UNINITIALIZED);
-            addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, false, null);
-            returnBuilder.end();
-        } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
-            emitEncounteredSynthetic(builder, getSpecialization().getNode(), specialization);
-        } else {
-            returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null));
-        }
-
-        if (!returnBuilder.isEmpty()) {
-            TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
-            TypeData sourceType = specialization.getReturnType().getTypeSystemType();
-
-            builder.startReturn();
-            if (targetType == null || sourceType == null) {
-                builder.tree(returnBuilder.build());
-            } else if (sourceType.needsCastTo(targetType)) {
-                CodeTree cast;
-                if (executable.hasUnexpectedValue(context)) {
-                    cast = TypeSystemCodeGenerator.expect(targetType, returnBuilder.build());
-                } else {
-                    cast = TypeSystemCodeGenerator.cast(targetType, returnBuilder.build());
-                }
-                builder.tree(cast);
-            } else {
-                builder.tree(returnBuilder.build());
-            }
-            builder.end();
-        }
-
-        if (!specialization.getExceptions().isEmpty()) {
-            for (SpecializationThrowsData exception : specialization.getExceptions()) {
-                builder.end().startCatchBlock(exception.getJavaClass(), "ex");
-                builder.tree(createDeoptimize(builder));
-                builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), null, "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass())));
-            }
-            builder.end();
-        }
-        if (!specialization.getAssumptions().isEmpty()) {
-            builder.end().startCatchBlock(context.getTruffleTypes().getInvalidAssumption(), "ex");
-            builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), null, "Assumption failed"));
-            builder.end();
-        }
-
-        return builder.build();
-    }
-
-    private CodeExecutableElement createCopyConstructorFactoryMethod(CodeTypeElement clazz, TypeMirror baseType) {
-        List<Parameter> implicitTypeParams = getImplicitTypeParameters(specialization);
-        String baseName = "current";
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), NodeFactoryFactory.FACTORY_METHOD_NAME);
-        method.addParameter(new CodeVariableElement(specialization.getNode().getNodeType(), baseName));
-        for (Parameter implicitTypeParam : implicitTypeParams) {
-            method.addParameter(new CodeVariableElement(context.getType(Class.class), implicitTypeName(implicitTypeParam)));
-        }
-        CodeTreeBuilder builder = method.createBuilder();
-        builder.startReturn();
-        builder.startNew(clazz.asType());
-        builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end();
-        for (Parameter param : implicitTypeParams) {
-            builder.string(implicitTypeName(param));
-        }
-        builder.end().end();
-        return method;
-    }
-
-    private CodeExecutableElement createConstructorFactoryMethod(CodeTypeElement clazz, ExecutableElement constructor) {
-        List<? extends VariableElement> parameters = constructor.getParameters();
-        CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), NodeFactoryFactory.FACTORY_METHOD_NAME,
-                        parameters.toArray(new CodeVariableElement[parameters.size()]));
-        CodeTreeBuilder builder = method.createBuilder();
-        builder.startReturn();
-        builder.startNew(clazz.asType());
-        for (VariableElement param : parameters) {
-            builder.string(((CodeVariableElement) param).getName());
-        }
-        builder.end().end();
-        return method;
-    }
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Thu Feb 12 04:01:46 2015 +0100
@@ -118,14 +118,6 @@
         return builder.build();
     }
 
-    public static CodeTree cast(TypeData sourceType, TypeData targetType, CodeTree content) {
-        if (sourceType != null && !sourceType.needsCastTo(targetType)) {
-            return content;
-        } else {
-            return cast(targetType, content);
-        }
-    }
-
     public static CodeTree expect(TypeData type, CodeTree content) {
         if (type.isGeneric() || type.isVoid()) {
             return content;
@@ -208,15 +200,13 @@
     public CodeTypeElement create(ProcessorContext context, TypeSystemData typeSystem) {
         CodeTypeElement clazz = new TypeClassFactory(context, typeSystem).create();
 
-        if (typeSystem.getOptions().useNewLayout()) {
-            clazz.add(new TypeSystemNodeFactory(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());
-                    }
+        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());
                 }
             }
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Feb 12 04:01:46 2015 +0100
@@ -119,16 +119,6 @@
         return b.toString();
     }
 
-    public static VariableElement findVariableElement(DeclaredType type, String name) {
-        List<? extends VariableElement> elements = ElementFilter.fieldsIn(type.asElement().getEnclosedElements());
-        for (VariableElement variableElement : elements) {
-            if (variableElement.getSimpleName().toString().equals(name)) {
-                return variableElement;
-            }
-        }
-        return null;
-    }
-
     public static TypeMirror boxType(ProcessorContext context, TypeMirror primitiveType) {
         TypeMirror boxedType = primitiveType;
         if (boxedType.getKind().isPrimitive()) {
@@ -191,8 +181,17 @@
     }
 
     public static String getReadableSignature(ExecutableElement method) {
-        // TODO toString does not guarantee a good signature
-        return method.toString();
+        StringBuilder builder = new StringBuilder();
+        builder.append(method.getSimpleName().toString());
+        builder.append("(");
+        String sep = "";
+        for (VariableElement var : method.getParameters()) {
+            builder.append(sep);
+            builder.append(getSimpleName(var.asType()));
+            sep = ", ";
+        }
+        builder.append(")");
+        return builder.toString();
     }
 
     public static boolean hasError(TypeMirror mirror) {
@@ -588,29 +587,6 @@
         return types;
     }
 
-    public static List<TypeMirror> getAssignableTypes(ProcessorContext context, TypeMirror type) {
-        if (isPrimitive(type)) {
-            return Arrays.asList(type, boxType(context, type), context.getType(Object.class));
-        } else if (type.getKind() == TypeKind.ARRAY) {
-            return Arrays.asList(type, context.getType(Object.class));
-        } else if (type.getKind() == TypeKind.DECLARED) {
-            DeclaredType declaredType = (DeclaredType) type;
-            TypeElement typeElement = fromTypeMirror(declaredType);
-            List<TypeElement> types = getSuperTypes(typeElement);
-            List<TypeMirror> mirrors = new ArrayList<>(types.size());
-            mirrors.add(type);
-            for (TypeElement superTypeElement : types) {
-                mirrors.add(superTypeElement.asType());
-            }
-            if (typeElement.getKind().isInterface()) {
-                mirrors.add(getType(context.getEnvironment(), Object.class));
-            }
-            return mirrors;
-        } else {
-            return Collections.emptyList();
-        }
-    }
-
     /**
      * Gets the element representing the {@linkplain TypeElement#getSuperclass() super class} of a
      * given type element.
@@ -690,6 +666,8 @@
                 return pack.getQualifiedName().toString();
             case ARRAY:
                 return getSimpleName(((ArrayType) mirror).getComponentType());
+            case EXECUTABLE:
+                return null;
             default:
                 throw new RuntimeException("Unknown type specified " + mirror.getKind());
         }
@@ -854,14 +832,16 @@
 
     public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List<? extends AnnotationMirror> mirrors, Class<?> annotationClass) {
         TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName());
-        return findAnnotationMirror(mirrors, expectedAnnotationType);
+        return findAnnotationMirror(mirrors, expectedAnnotationType.asType());
     }
 
     public static AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeElement expectedAnnotationType) {
+        return findAnnotationMirror(mirrors, expectedAnnotationType.asType());
+    }
+
+    public static AnnotationMirror findAnnotationMirror(List<? extends AnnotationMirror> mirrors, TypeMirror expectedAnnotationType) {
         for (AnnotationMirror mirror : mirrors) {
-            DeclaredType annotationType = mirror.getAnnotationType();
-            TypeElement actualAnnotationType = (TypeElement) annotationType.asElement();
-            if (actualAnnotationType.equals(expectedAnnotationType)) {
+            if (typeEquals(mirror.getAnnotationType(), expectedAnnotationType)) {
                 return mirror;
             }
         }
@@ -1079,42 +1059,53 @@
         return new DeclaredCodeTypeMirror((TypeElement) declaredType.asElement());
     }
 
-    public static ExecutableElement findMethod(TypeElement type, Set<Modifier> includeModifiers, Set<Modifier> excludeModifiers, String methodName, List<TypeMirror> types) {
-        outer: for (ExecutableElement executable : ElementFilter.methodsIn(type.getEnclosedElements())) {
-            if (includeModifiers != null) {
-                if (!executable.getModifiers().containsAll(includeModifiers)) {
-                    continue;
-                }
-            }
-            if (excludeModifiers != null) {
-                if (executable.getModifiers().containsAll(excludeModifiers)) {
-                    continue;
-                }
-            }
-            if (!executable.getSimpleName().toString().equals(methodName)) {
-                continue;
-            }
-            if (types.size() != executable.getParameters().size()) {
-                continue;
-            }
-            for (int i = 0; i < types.size(); i++) {
-                TypeMirror var1 = types.get(i);
-                VariableElement var2 = executable.getParameters().get(i);
-                if (ElementUtils.typeEquals(var1, var2.asType())) {
-                    continue outer;
-                }
-            }
-            return executable;
+    public static boolean variableEquals(VariableElement var1, VariableElement var2) {
+        if (!var1.getSimpleName().equals(var2.getSimpleName())) {
+            return false;
         }
-        return null;
+        if (!ElementUtils.typeEquals(var1.asType(), var2.asType())) {
+            return false;
+        }
+        if (!ElementUtils.elementEquals(var1.getEnclosingElement(), var2.getEnclosingElement())) {
+            return false;
+        }
+        return true;
     }
 
-    public static List<TypeMirror> asTypes(List<? extends Element> elements) {
-        List<TypeMirror> types = new ArrayList<>(elements.size());
-        for (Element element : elements) {
-            types.add(element.asType());
+    public static boolean executableEquals(ExecutableElement var1, ExecutableElement var2) {
+        if (!var1.getSimpleName().equals(var2.getSimpleName())) {
+            return false;
+        }
+        if (var1.getParameters().size() != var2.getParameters().size()) {
+            return false;
+        }
+        if (!ElementUtils.typeEquals(var1.asType(), var2.asType())) {
+            return false;
         }
-        return types;
+        if (!ElementUtils.elementEquals(var1.getEnclosingElement(), var2.getEnclosingElement())) {
+            return false;
+        }
+        for (int i = 0; i < var1.getParameters().size(); i++) {
+            if (!typeEquals(var1.getParameters().get(i).asType(), var2.getParameters().get(i).asType())) {
+                return false;
+            }
+        }
+        return true;
     }
 
+    public static boolean elementEquals(Element element1, Element element2) {
+        if (element1.getKind() != element2.getKind()) {
+            return false;
+        } else if (element1 instanceof VariableElement) {
+            return variableEquals((VariableElement) element1, (VariableElement) element2);
+        } else if (element1 instanceof ExecutableElement) {
+            return executableEquals((ExecutableElement) element1, (ExecutableElement) element2);
+        } else if (element1 instanceof TypeElement) {
+            return typeEquals(element1.asType(), element2.asType());
+        } else if (element1 instanceof PackageElement) {
+            return element1.getSimpleName().equals(element2.getSimpleName());
+        } else {
+            throw new AssertionError("unsupported element type");
+        }
+    }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Thu Feb 12 04:01:46 2015 +0100
@@ -77,11 +77,11 @@
     }
 
     public static CodeTree singleString(String s) {
-        return new CodeTreeBuilder(null).string(s).getTree();
+        return createBuilder().string(s).build();
     }
 
     public static CodeTree singleType(TypeMirror s) {
-        return new CodeTreeBuilder(null).type(s).getTree();
+        return createBuilder().type(s).build();
     }
 
     private CodeTreeBuilder push(CodeTreeKind kind) {
@@ -324,10 +324,6 @@
         return end();
     }
 
-    public CodeTreeBuilder dot() {
-        return string(".");
-    }
-
     public CodeTreeBuilder newLine() {
         return push(NEW_LINE);
     }
@@ -576,17 +572,6 @@
         return declaration(type, name, init.getTree());
     }
 
-    public CodeTreeBuilder declaration(String type, String name, CodeTreeBuilder init) {
-        if (init == this) {
-            throw new IllegalArgumentException("Recursive builder usage.");
-        }
-        return declaration(type, name, init.getTree());
-    }
-
-    public CodeTreeBuilder declaration(TypeMirror type, String name) {
-        return declaration(type, name, (CodeTree) null);
-    }
-
     public CodeTreeBuilder create() {
         return new CodeTreeBuilder(this);
     }
@@ -622,11 +607,6 @@
         return root;
     }
 
-    public CodeTreeBuilder cast(String baseClassName) {
-        string("(").string(baseClassName).string(") ");
-        return this;
-    }
-
     public CodeTreeBuilder cast(TypeMirror type) {
         string("(").type(type).string(") ");
         return this;
@@ -671,22 +651,10 @@
         return startReturn().string("true").end();
     }
 
-    public CodeTreeBuilder instanceOf(CodeTree var, CodeTree type) {
-        return tree(var).string(" instanceof ").tree(type);
-    }
-
     public CodeTreeBuilder instanceOf(CodeTree var, TypeMirror type) {
         return tree(var).string(" instanceof ").type(type);
     }
 
-    public CodeTreeBuilder instanceOf(String var, String type) {
-        return instanceOf(singleString(var), singleString(type));
-    }
-
-    public CodeTreeBuilder instanceOf(String var, TypeMirror type) {
-        return instanceOf(singleString(var), singleType(type));
-    }
-
     public CodeTreeBuilder defaultValue(TypeMirror mirror) {
         switch (mirror.getKind()) {
             case VOID:
@@ -717,26 +685,6 @@
         }
     }
 
-    public CodeTreeBuilder assertFalse() {
-        return startAssert().string("false").end();
-    }
-
-    public CodeTreeBuilder breakStatement() {
-        return statement("break");
-    }
-
-    public CodeTreeBuilder isNull() {
-        return string(" == null");
-    }
-
-    public CodeTreeBuilder isNotNull() {
-        return string(" != null");
-    }
-
-    public CodeTreeBuilder is(CodeTree tree) {
-        return string(" == ").tree(tree);
-    }
-
     public CodeTreeBuilder startTryBlock() {
         return string("try ").startBlock();
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeElement.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeElement.java	Thu Feb 12 04:01:46 2015 +0100
@@ -173,15 +173,6 @@
         return ElementFilter.fieldsIn(getEnclosedElements());
     }
 
-    public ExecutableElement getMethod(String name) {
-        for (Element element : getEnclosedElements()) {
-            if (element.getKind() == ElementKind.METHOD && element.getSimpleName().toString().equals(name)) {
-                return (ExecutableElement) element;
-            }
-        }
-        return null;
-    }
-
     public List<ExecutableElement> getMethods() {
         return ElementFilter.methodsIn(getEnclosedElements());
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeVariableElement.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeVariableElement.java	Thu Feb 12 04:01:46 2015 +0100
@@ -85,6 +85,11 @@
     }
 
     @Override
+    public String toString() {
+        return super.toString() + "/* " + ElementUtils.getSimpleName(type) + "*/";
+    }
+
+    @Override
     public ElementKind getKind() {
         if (getEnclosingElement() instanceof ExecutableElement) {
             return ElementKind.PARAMETER;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AnnotatedParameterSpec.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.dsl.processor.model;
+
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.dsl.processor.java.*;
+
+public final class AnnotatedParameterSpec extends ParameterSpec {
+
+    private final DeclaredType annotationType;
+
+    public AnnotatedParameterSpec(DeclaredType type) {
+        super("annotated", Collections.<TypeMirror> emptyList());
+        this.annotationType = type;
+    }
+
+    public DeclaredType getAnnotationType() {
+        return annotationType;
+    }
+
+    @Override
+    public boolean matches(VariableElement variable) {
+        if (ElementUtils.findAnnotationMirror(variable.getAnnotationMirrors(), annotationType) != null) {
+            return true;
+        }
+        return false;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/AssumptionExpression.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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 javax.lang.model.element.*;
+
+import com.oracle.truffle.dsl.processor.expression.*;
+import com.oracle.truffle.dsl.processor.java.*;
+
+public final class AssumptionExpression extends MessageContainer {
+
+    private final TemplateMethod source;
+    private final DSLExpression expression;
+    private final String id;
+
+    public AssumptionExpression(TemplateMethod source, DSLExpression expression, String id) {
+        this.source = source;
+        this.expression = expression;
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return source.getMessageElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return source.getMessageAnnotation();
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return ElementUtils.getAnnotationValue(getMessageAnnotation(), "assumptions");
+    }
+
+    public DSLExpression getExpression() {
+        return expression;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/CacheExpression.java	Thu Feb 12 04:01:46 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * 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 javax.lang.model.element.*;
+
+import com.oracle.truffle.dsl.processor.expression.*;
+import com.oracle.truffle.dsl.processor.java.*;
+
+public final class CacheExpression extends MessageContainer {
+
+    private final DSLExpression expression;
+    private final Parameter sourceParameter;
+    private final AnnotationMirror sourceAnnotationMirror;
+
+    public CacheExpression(Parameter sourceParameter, AnnotationMirror sourceAnnotationMirror, DSLExpression expression) {
+        this.sourceParameter = sourceParameter;
+        this.expression = expression;
+        this.sourceAnnotationMirror = sourceAnnotationMirror;
+    }
+
+    public Parameter getParameter() {
+        return sourceParameter;
+    }
+
+    @Override
+    public Element getMessageElement() {
+        return sourceParameter.getVariableElement();
+    }
+
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return sourceAnnotationMirror;
+    }
+
+    @Override
+    public AnnotationValue getMessageAnnotationValue() {
+        return ElementUtils.getAnnotationValue(getMessageAnnotation(), "value");
+    }
+
+    public DSLExpression getExpression() {
+        return expression;
+    }
+
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -85,12 +85,4 @@
         return super.equals(obj);
     }
 
-    public boolean hasFrame() {
-        return getFrame() != null;
-    }
-
-    public Parameter getFrame() {
-        return findParameter("frameValue");
-    }
-
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardData.java	Thu Feb 12 03:42:51 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +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.*;
-
-public class GuardData extends TemplateMethod {
-
-    private List<GuardExpression> impliesExpressions;
-
-    public GuardData(TemplateMethod method, List<GuardExpression> impliesExpressions) {
-        super(method);
-        this.impliesExpressions = impliesExpressions;
-    }
-
-    public List<GuardExpression> getImpliesExpressions() {
-        return impliesExpressions;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof GuardData) {
-            GuardData other = (GuardData) obj;
-            return getMethod().equals(other.getMethod());
-        }
-        return false;
-    }
-
-    @Override
-    public int hashCode() {
-        return getMethod().hashCode();
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,120 +24,63 @@
 
 import java.util.*;
 
-public final class GuardExpression {
-
-    private GuardData resolvedGuard;
-    private NodeExecutionData[] resolvedChildren;
-
-    private final String guardName;
-    private final boolean negated;
-    private final String[] childNames;
+import javax.lang.model.element.*;
 
-    public GuardExpression(String expression, boolean allowArguments) {
-        String exp = expression;
-        if (exp.startsWith("!")) {
-            exp = exp.substring(1, exp.length());
-            negated = true;
-        } else {
-            negated = false;
-        }
+import com.oracle.truffle.dsl.processor.expression.*;
+import com.oracle.truffle.dsl.processor.expression.DSLExpression.Negate;
+import com.oracle.truffle.dsl.processor.java.*;
 
-        int argumentStart = exp.indexOf('(');
-        int endIndex = exp.lastIndexOf(')');
-        if (allowArguments && argumentStart != -1 && endIndex != -1) {
-            guardName = exp.substring(0, argumentStart).trim();
-            String arguments = exp.substring(argumentStart + 1, endIndex);
-            String[] children = arguments.split(",");
-            for (int i = 0; i < children.length; i++) {
-                children[i] = children[i].trim();
-            }
-            if (children.length == 1 && children[0].isEmpty()) {
-                childNames = new String[0];
-            } else {
-                childNames = children;
-            }
-        } else {
-            guardName = exp;
-            childNames = null;
-        }
+public final class GuardExpression extends MessageContainer {
+
+    private final TemplateMethod source;
+    private final DSLExpression expression;
+
+    public GuardExpression(TemplateMethod source, DSLExpression expression) {
+        this.source = source;
+        this.expression = expression;
     }
 
-    public String[] getChildNames() {
-        return childNames;
-    }
-
-    public boolean isResolved() {
-        return resolvedGuard != null;
+    @Override
+    public Element getMessageElement() {
+        return source.getMessageElement();
     }
 
-    public String getGuardName() {
-        return guardName;
-    }
-
-    public NodeExecutionData[] getResolvedChildren() {
-        return resolvedChildren;
-    }
-
-    public void setResolvedChildren(NodeExecutionData[] resolvedChildren) {
-        this.resolvedChildren = resolvedChildren;
-    }
-
-    public void setResolvedGuard(GuardData guard) {
-        this.resolvedGuard = guard;
+    @Override
+    public AnnotationMirror getMessageAnnotation() {
+        return source.getMessageAnnotation();
     }
 
     @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
+    public AnnotationValue getMessageAnnotationValue() {
+        return ElementUtils.getAnnotationValue(getMessageAnnotation(), "guards");
+    }
+
+    public DSLExpression getExpression() {
+        return expression;
+    }
+
+    public boolean equalsNegated(GuardExpression other) {
+        boolean negated = false;
+        DSLExpression thisExpression = expression;
+        if (thisExpression instanceof Negate) {
+            negated = true;
+            thisExpression = ((Negate) thisExpression).getReceiver();
+        }
+
+        boolean otherNegated = false;
+        DSLExpression otherExpression = other.expression;
+        if (otherExpression instanceof Negate) {
+            otherNegated = true;
+            otherExpression = ((Negate) otherExpression).getReceiver();
+        }
+        return Objects.equals(thisExpression, otherExpression) && negated != otherNegated;
+    }
+
+    public boolean implies(GuardExpression other) {
+        if (Objects.equals(expression, other.expression)) {
             return true;
-        } else if (obj instanceof GuardExpression) {
-            GuardExpression other = (GuardExpression) obj;
-            if (isResolved() && other.isResolved()) {
-                return resolvedGuard.equals(other.resolvedGuard) && negated == other.negated && Arrays.equals(resolvedChildren, other.resolvedChildren);
-            } else {
-                boolean equal = guardName.equals(other.guardName) && negated == other.negated;
-                if (childNames != null && other.childNames != null) {
-                    equal &= Arrays.equals(childNames, other.childNames);
-                }
-                return equal;
-            }
         }
         return false;
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(guardName, negated, resolvedGuard, resolvedChildren);
-    }
-
-    public boolean implies(GuardExpression other) {
-        if (equals(other)) {
-            return true;
-        }
-
-        if (isResolved() && other.isResolved()) {
-            for (GuardExpression implies : getResolvedGuard().getImpliesExpressions()) {
-                if (implies.getGuardName().equals(other.getGuardName())) {
-                    if (implies.isNegated() == other.isNegated()) {
-                        return true;
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return (negated ? "!" : "") + guardName;
-    }
-
-    public boolean isNegated() {
-        return negated;
-    }
-
-    public GuardData getResolvedGuard() {
-        return resolvedGuard;
-    }
-
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java	Thu Feb 12 04:01:46 2015 +0100
@@ -119,7 +119,7 @@
         TypeElement expectError = context.getTruffleTypes().getExpectError();
         if (expectError != null) {
             Element element = getMessageElement();
-            AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError);
+            AnnotationMirror mirror = ElementUtils.findAnnotationMirror(element.getAnnotationMirrors(), expectError.asType());
             if (mirror != null) {
                 List<String> values = ElementUtils.getAnnotationValueList(String.class, mirror, "value");
                 if (values == null) {
@@ -149,7 +149,7 @@
 
         TypeElement expectError = context.getTruffleTypes().getExpectError();
         if (expectError != null) {
-            AnnotationMirror mirror = ElementUtils.findAnnotationMirror(messageElement.getAnnotationMirrors(), expectError);
+            AnnotationMirror mirror = ElementUtils.findAnnotationMirror(messageElement.getAnnotationMirrors(), expectError.asType());
             if (mirror != null) {
                 List<String> expectedTexts = ElementUtils.getAnnotationValueList(String.class, mirror, "value");
                 boolean found = false;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java	Thu Feb 12 04:01:46 2015 +0100
@@ -33,6 +33,7 @@
     private final ParameterSpec returnType;
     private final List<ParameterSpec> optional = new ArrayList<>();
     private final List<ParameterSpec> required = new ArrayList<>();
+    private final List<ParameterSpec> annotations = new ArrayList<>();
 
     private boolean ignoreAdditionalParameters;
     private boolean ignoreAdditionalSpecifications;
@@ -69,6 +70,10 @@
         return spec;
     }
 
+    public List<ParameterSpec> getAnnotations() {
+        return annotations;
+    }
+
     public ParameterSpec getReturnType() {
         return returnType;
     }
@@ -89,15 +94,6 @@
         return specs;
     }
 
-    public ParameterSpec findParameterSpec(String name) {
-        for (ParameterSpec spec : getAll()) {
-            if (spec.getName().equals(name)) {
-                return spec;
-            }
-        }
-        return null;
-    }
-
     public void applyTypeDefinitions(String prefix) {
         this.typeDefinitions = createTypeDefinitions(prefix);
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -52,7 +52,7 @@
     private final Element accessElement;
     private final Cardinality cardinality;
 
-    private List<NodeChildData> executeWith = Collections.emptyList();
+    private List<NodeExecutionData> executeWith = Collections.emptyList();
 
     private NodeData childNode;
 
@@ -66,11 +66,11 @@
         this.cardinality = cardinality;
     }
 
-    public List<NodeChildData> getExecuteWith() {
+    public List<NodeExecutionData> getExecuteWith() {
         return executeWith;
     }
 
-    public void setExecuteWith(List<NodeChildData> executeWith) {
+    public void setExecuteWith(List<NodeExecutionData> executeWith) {
         this.executeWith = executeWith;
     }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -42,7 +42,6 @@
     private final List<NodeChildData> children;
     private final List<NodeExecutionData> childExecutions;
     private final List<NodeFieldData> fields;
-    private final List<String> assumptions;
 
     private ParameterSpec instanceParameterSpec;
 
@@ -64,7 +63,6 @@
         this.fields = new ArrayList<>();
         this.children = new ArrayList<>();
         this.childExecutions = new ArrayList<>();
-        this.assumptions = new ArrayList<>();
         this.thisExecution = new NodeExecutionData(new NodeChildData(null, null, "this", getNodeType(), getNodeType(), null, Cardinality.ONE), -1, false);
         this.thisExecution.getChild().setNode(this);
         this.generateFactory = generateFactory;
@@ -148,17 +146,13 @@
             if (!specialization.isReachable()) {
                 continue;
             }
-            if (specialization.isFrameUsedByGuard()) {
+            if (specialization.isFrameUsed()) {
                 return true;
             }
         }
         return false;
     }
 
-    public boolean isPolymorphic(ProcessorContext context) {
-        return needsRewrites(context);
-    }
-
     public List<CreateCastData> getCasts() {
         return casts;
     }
@@ -221,10 +215,6 @@
         return getTemplateType().asType();
     }
 
-    public List<String> getAssumptions() {
-        return assumptions;
-    }
-
     public boolean needsFactory() {
         if (specializations == null) {
             return false;
@@ -243,7 +233,7 @@
     public boolean supportsFrame() {
         if (executableTypes != null) {
             for (ExecutableTypeData execType : getExecutableTypes(-1)) {
-                if (execType.findParameter("frameValue") == null) {
+                if (execType.findParameter(TemplateMethod.FRAME_NAME) == null) {
                     return false;
                 }
             }
@@ -431,7 +421,6 @@
         dumpProperty(builder, indent, "fields", getChildren());
         dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
         dumpProperty(builder, indent, "specializations", getSpecializations());
-        dumpProperty(builder, indent, "assumptions", getAssumptions());
         dumpProperty(builder, indent, "casts", getCasts());
         dumpProperty(builder, indent, "messages", collectMessages());
         if (getEnclosingNodes().size() > 0) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -74,11 +74,11 @@
         return shortCircuit;
     }
 
-    public String getShortCircuitId() {
-        return createShortCircuitId(child, index);
+    public String getIndexedName() {
+        return createIndexedName(child, index);
     }
 
-    public static String createShortCircuitId(NodeChildData child, int varArgsIndex) {
+    public static String createIndexedName(NodeChildData child, int varArgsIndex) {
         String shortCircuitName = child.getName();
         if (child.getCardinality().isMany()) {
             shortCircuitName = shortCircuitName + "[" + varArgsIndex + "]";
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -29,17 +29,19 @@
 
     private final Element messageElement;
     private final AnnotationMirror messageAnnotation;
-    private final String name;
-    private final TypeMirror type;
     private final boolean generated;
     private ExecutableElement getter;
+    private final VariableElement variable;
 
-    public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, TypeMirror type, String name, boolean generated) {
+    public NodeFieldData(Element messageElement, AnnotationMirror messageAnnotation, VariableElement variableElement, boolean generated) {
         this.messageElement = messageElement;
         this.messageAnnotation = messageAnnotation;
-        this.name = name;
-        this.type = type;
         this.generated = generated;
+        this.variable = variableElement;
+    }
+
+    public VariableElement getVariable() {
+        return variable;
     }
 
     public void setGetter(ExecutableElement getter) {
@@ -57,11 +59,11 @@
     }
 
     public String getName() {
-        return name;
+        return variable.getSimpleName().toString();
     }
 
     public TypeMirror getType() {
-        return type;
+        return variable.asType();
     }
 
     public boolean isGenerated() {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java	Thu Feb 12 04:01:46 2015 +0100
@@ -22,23 +22,23 @@
  */
 package com.oracle.truffle.dsl.processor.model;
 
+import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
-import com.oracle.truffle.dsl.processor.java.*;
-
 public final class Parameter {
 
     private final ParameterSpec specification;
     private TypeData typeSystemType;
     private TemplateMethod method;
-    private final String localName;
+    private String localName;
     private final int specificationVarArgsIndex;
     private final int typeVarArgsIndex;
-    private final TypeMirror actualType;
+
+    private final VariableElement variableElement;
 
-    public Parameter(ParameterSpec specification, TypeMirror actualType, int specificationVarArgsIndex, int typeVarArgsIndex) {
+    public Parameter(ParameterSpec specification, VariableElement variableElement, int specificationVarArgsIndex, int typeVarArgsIndex) {
         this.specification = specification;
-        this.actualType = actualType;
+        this.variableElement = variableElement;
         this.typeSystemType = null;
 
         this.specificationVarArgsIndex = specificationVarArgsIndex;
@@ -51,22 +51,30 @@
         this.localName = valueName;
     }
 
-    public Parameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex) {
-        this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex);
+    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.specificationVarArgsIndex, parameter.typeVarArgsIndex);
+        this(parameter.specification, otherType, parameter.variableElement, parameter.specificationVarArgsIndex, parameter.typeVarArgsIndex);
     }
 
     public Parameter(Parameter parameter) {
         this.specification = parameter.specification;
-        this.actualType = parameter.actualType;
         this.typeSystemType = parameter.typeSystemType;
         this.specificationVarArgsIndex = parameter.specificationVarArgsIndex;
         this.localName = parameter.localName;
         this.typeVarArgsIndex = parameter.typeVarArgsIndex;
+        this.variableElement = parameter.variableElement;
+    }
+
+    public void setLocalName(String localName) {
+        this.localName = localName;
+    }
+
+    public VariableElement getVariableElement() {
+        return variableElement;
     }
 
     public int getTypeVarArgsIndex() {
@@ -94,7 +102,7 @@
     }
 
     public TypeMirror getType() {
-        return actualType;
+        return variableElement.asType();
     }
 
     public TypeData getTypeSystemType() {
@@ -111,6 +119,7 @@
 
     @Override
     public String toString() {
-        return ElementUtils.getSimpleName(actualType);
+        return "Parameter [localName=" + localName + ", type=" + getType() + ", variableElement=" + variableElement + "]";
     }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import javax.lang.model.element.*;
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.dsl.processor.java.*;
@@ -114,8 +115,11 @@
         return allowedTypes;
     }
 
-    public boolean matches(TypeMirror actualType) {
-        return allowedTypesIdentifier.contains(ElementUtils.getUniqueIdentifier(actualType));
+    public boolean matches(VariableElement variable) {
+        if (allowedTypesIdentifier != null) {
+            return allowedTypesIdentifier.contains(ElementUtils.getUniqueIdentifier(variable.asType()));
+        }
+        return true;
     }
 
     @Override
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,7 +24,10 @@
 
 import java.util.*;
 
+import javax.lang.model.element.*;
+
 import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.expression.*;
 import com.oracle.truffle.dsl.processor.java.*;
 
 public final class SpecializationData extends TemplateMethod {
@@ -40,8 +43,9 @@
     private final SpecializationKind kind;
     private final List<SpecializationThrowsData> exceptions;
     private List<GuardExpression> guards = Collections.emptyList();
+    private List<CacheExpression> caches = Collections.emptyList();
+    private List<AssumptionExpression> assumptionExpressions = Collections.emptyList();
     private List<ShortCircuitData> shortCircuits;
-    private List<String> assumptions = Collections.emptyList();
     private final Set<SpecializationData> contains = new TreeSet<>();
     private final Set<String> containsNames = new TreeSet<>();
     private final Set<SpecializationData> excludedBy = new TreeSet<>();
@@ -49,6 +53,7 @@
     private SpecializationData insertBefore;
     private boolean reachable;
     private int index;
+    private DSLExpression limitExpression;
 
     public SpecializationData(NodeData node, TemplateMethod template, SpecializationKind kind, List<SpecializationThrowsData> exceptions) {
         super(template);
@@ -62,6 +67,57 @@
         }
     }
 
+    public boolean isCacheBoundByGuard(CacheExpression cacheExpression) {
+        for (GuardExpression expression : getGuards()) {
+            if (expression.getExpression().findBoundVariableElements().contains(cacheExpression.getParameter().getVariableElement())) {
+                return true;
+            }
+        }
+
+        // check all next binding caches if they are bound by guard
+        Set<VariableElement> boundVariables = cacheExpression.getExpression().findBoundVariableElements();
+        boolean found = false;
+        for (CacheExpression expression : getCaches()) {
+            if (cacheExpression == expression) {
+                found = true;
+            } else if (found) {
+                if (boundVariables.contains(expression.getParameter().getVariableElement())) {
+                    if (isCacheBoundByGuard(expression)) {
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    public boolean isDynamicParameterBound(DSLExpression expression) {
+        Set<VariableElement> boundVariables = expression.findBoundVariableElements();
+        for (Parameter parameter : getDynamicParameters()) {
+            if (boundVariables.contains(parameter.getVariableElement())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public Parameter findByVariable(VariableElement variable) {
+        for (Parameter parameter : getParameters()) {
+            if (ElementUtils.variableEquals(parameter.getVariableElement(), variable)) {
+                return parameter;
+            }
+        }
+        return null;
+    }
+
+    public DSLExpression getLimitExpression() {
+        return limitExpression;
+    }
+
+    public void setLimitExpression(DSLExpression limitExpression) {
+        this.limitExpression = limitExpression;
+    }
+
     public void setInsertBefore(SpecializationData insertBefore) {
         this.insertBefore = insertBefore;
     }
@@ -106,6 +162,14 @@
         return kind == SpecializationKind.POLYMORPHIC;
     }
 
+    public List<Parameter> getDynamicParameters() {
+        List<Parameter> uncachedParameters = new ArrayList<>(getParameters());
+        for (CacheExpression cacheExpression : getCaches()) {
+            uncachedParameters.remove(cacheExpression.getParameter());
+        }
+        return uncachedParameters;
+    }
+
     @Override
     protected List<MessageContainer> findChildContainers() {
         List<MessageContainer> sinks = new ArrayList<>();
@@ -113,11 +177,13 @@
             sinks.addAll(exceptions);
         }
         if (guards != null) {
-            for (GuardExpression guard : guards) {
-                if (guard.isResolved()) {
-                    sinks.add(guard.getResolvedGuard());
-                }
-            }
+            sinks.addAll(guards);
+        }
+        if (caches != null) {
+            sinks.addAll(caches);
+        }
+        if (assumptionExpressions != null) {
+            sinks.addAll(assumptionExpressions);
         }
         return sinks;
     }
@@ -129,9 +195,10 @@
         if (!getGuards().isEmpty()) {
             return true;
         }
-        if (!getAssumptions().isEmpty()) {
+        if (!getAssumptionExpressions().isEmpty()) {
             return true;
         }
+
         for (Parameter parameter : getSignatureParameters()) {
             NodeChildData child = parameter.getSpecification().getExecution().getChild();
             ExecutableTypeData type = child.findExecutableType(parameter.getTypeSystemType());
@@ -183,48 +250,6 @@
         return index;
     }
 
-    public boolean isContainedBy(SpecializationData next) {
-        if (compareTo(next) > 0) {
-            // must be declared after the current specialization
-            return false;
-        }
-
-        Iterator<Parameter> currentSignature = getSignatureParameters().iterator();
-        Iterator<Parameter> nextSignature = next.getSignatureParameters().iterator();
-
-        while (currentSignature.hasNext() && nextSignature.hasNext()) {
-            TypeData currentType = currentSignature.next().getTypeSystemType();
-            TypeData prevType = nextSignature.next().getTypeSystemType();
-
-            if (!currentType.isImplicitSubtypeOf(prevType)) {
-                return false;
-            }
-        }
-
-        for (String nextAssumption : next.getAssumptions()) {
-            if (!getAssumptions().contains(nextAssumption)) {
-                return false;
-            }
-        }
-
-        Iterator<GuardExpression> nextGuards = next.getGuards().iterator();
-        while (nextGuards.hasNext()) {
-            GuardExpression nextGuard = nextGuards.next();
-            boolean implied = false;
-            for (GuardExpression currentGuard : getGuards()) {
-                if (currentGuard.implies(nextGuard)) {
-                    implied = true;
-                    break;
-                }
-            }
-            if (!implied) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
     public NodeData getNode() {
         return node;
     }
@@ -261,14 +286,6 @@
         return shortCircuits;
     }
 
-    public List<String> getAssumptions() {
-        return assumptions;
-    }
-
-    public void setAssumptions(List<String> assumptions) {
-        this.assumptions = assumptions;
-    }
-
     public SpecializationData findNextSpecialization() {
         List<SpecializationData> specializations = node.getSpecializations();
         for (int i = 0; i < specializations.size() - 1; i++) {
@@ -284,19 +301,40 @@
         return String.format("%s [id = %s, method = %s, guards = %s, signature = %s]", getClass().getSimpleName(), getId(), getMethod(), getGuards(), getTypeSignature());
     }
 
-    public boolean isFrameUsedByGuard() {
-        for (GuardExpression guard : getGuards()) {
-            if (guard.getResolvedGuard() == null) {
-                continue;
-            }
+    public boolean isFrameUsed() {
+        return getFrame() != null;
+    }
+
+    public List<CacheExpression> getCaches() {
+        return caches;
+    }
+
+    public void setCaches(List<CacheExpression> caches) {
+        this.caches = caches;
+    }
+
+    public void setAssumptionExpressions(List<AssumptionExpression> assumptionExpressions) {
+        this.assumptionExpressions = assumptionExpressions;
+    }
 
-            for (Parameter param : guard.getResolvedGuard().getParameters()) {
-                if (ElementUtils.typeEquals(param.getType(), getNode().getFrameType())) {
-                    return true;
+    public List<AssumptionExpression> getAssumptionExpressions() {
+        return assumptionExpressions;
+    }
+
+    public boolean hasMultipleInstances() {
+        if (!getCaches().isEmpty()) {
+            for (GuardExpression guard : getGuards()) {
+                DSLExpression guardExpression = guard.getExpression();
+                Set<VariableElement> boundVariables = guardExpression.findBoundVariableElements();
+                if (isDynamicParameterBound(guardExpression)) {
+                    for (CacheExpression cache : getCaches()) {
+                        if (boundVariables.contains(cache.getParameter().getVariableElement())) {
+                            return true;
+                        }
+                    }
                 }
             }
         }
-
         return false;
     }
 
@@ -306,6 +344,12 @@
         }
 
         if (!prev.getExceptions().isEmpty()) {
+            // may get excluded by exception
+            return true;
+        }
+
+        if (hasMultipleInstances()) {
+            // may fallthrough due to limit
             return true;
         }
 
@@ -321,10 +365,10 @@
             }
         }
 
-        for (String prevAssumption : prev.getAssumptions()) {
-            if (!getAssumptions().contains(prevAssumption)) {
-                return true;
-            }
+        if (!prev.getAssumptionExpressions().isEmpty()) {
+            // TODO: chumer: we could at least check reachability after trivial assumptions
+            // not sure if this is worth it.
+            return true;
         }
 
         Iterator<GuardExpression> prevGuards = prev.getGuards().iterator();
@@ -339,4 +383,14 @@
 
         return false;
     }
+
+    public CacheExpression findCache(Parameter resolvedParameter) {
+        for (CacheExpression cache : getCaches()) {
+            if (cache.getParameter() == resolvedParameter) {
+                return cache;
+            }
+        }
+        return null;
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Thu Feb 12 04:01:46 2015 +0100
@@ -35,6 +35,7 @@
  */
 public class TemplateMethod extends MessageContainer implements Comparable<TemplateMethod> {
 
+    public static final String FRAME_NAME = "frameValue";
     public static final int NO_NATURAL_ORDER = -1;
 
     private String id;
@@ -68,6 +69,10 @@
         this.id = id;
     }
 
+    public final Parameter getFrame() {
+        return findParameter(FRAME_NAME);
+    }
+
     public String createReferenceName() {
         if (getMethod() == null) {
             return "-";
@@ -135,16 +140,6 @@
         }
     }
 
-    public List<Parameter> getRequiredParameters() {
-        List<Parameter> requiredParameters = new ArrayList<>();
-        for (Parameter parameter : getParameters()) {
-            if (getSpecification().getRequired().contains(parameter.getSpecification())) {
-                requiredParameters.add(parameter);
-            }
-        }
-        return requiredParameters;
-    }
-
     public Iterable<Parameter> getSignatureParameters() {
         return new FilteredIterable<>(getParameters(), new Predicate<Parameter>() {
             public boolean evaluate(Parameter value) {
@@ -157,16 +152,6 @@
         return parameters;
     }
 
-    public List<Parameter> findParameters(ParameterSpec spec) {
-        List<Parameter> foundParameters = new ArrayList<>();
-        for (Parameter param : getReturnTypeAndParameters()) {
-            if (param.getSpecification().getName().equals(spec.getName())) {
-                foundParameters.add(param);
-            }
-        }
-        return foundParameters;
-    }
-
     public Parameter findParameterOrDie(NodeExecutionData execution) {
         for (Parameter parameter : parameters) {
             if (parameter.getSpecification().isSignature() && parameter.getSpecification().getExecution() == execution) {
@@ -200,11 +185,6 @@
         return Collections.unmodifiableList(allParameters);
     }
 
-    public boolean canBeAccessedByInstanceOf(TypeMirror type) {
-        TypeMirror methodType = ElementUtils.findNearestEnclosingType(getMethod()).asType();
-        return ElementUtils.isAssignable(type, methodType) || ElementUtils.isAssignable(methodType, type);
-    }
-
     public ExecutableElement getMethod() {
         return method;
     }
@@ -258,20 +238,6 @@
         return signature;
     }
 
-    public Parameter getSignatureParameter(int searchIndex) {
-        int index = 0;
-        for (Parameter parameter : getParameters()) {
-            if (!parameter.getSpecification().isSignature()) {
-                continue;
-            }
-            if (index == searchIndex) {
-                return parameter;
-            }
-            index++;
-        }
-        return null;
-    }
-
     public void updateSignature(TypeSignature signature) {
         // TODO(CH): fails in normal usage - output ok though
         // assert signature.size() >= 1;
@@ -311,19 +277,6 @@
         return compare;
     }
 
-    public List<Parameter> getParametersAfter(Parameter genericParameter) {
-        boolean found = false;
-        List<Parameter> foundParameters = new ArrayList<>();
-        for (Parameter param : getParameters()) {
-            if (param.getLocalName().equals(genericParameter.getLocalName())) {
-                found = true;
-            } else if (found) {
-                foundParameters.add(param);
-            }
-        }
-        return foundParameters;
-    }
-
     public int compareBySignature(TemplateMethod compareMethod) {
         final TypeSystemData typeSystem = getTemplate().getTypeSystem();
         if (typeSystem != compareMethod.getTemplate().getTypeSystem()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Thu Feb 12 04:01:46 2015 +0100
@@ -146,15 +146,6 @@
         return result;
     }
 
-    public TypeData findType(String simpleName) {
-        for (TypeData type : types) {
-            if (ElementUtils.getTypeId(type.getBoxedType()).equals(simpleName)) {
-                return type;
-            }
-        }
-        return null;
-    }
-
     public TypeData findTypeData(TypeMirror type) {
         if (ElementUtils.typeEquals(voidType.getPrimitiveType(), type)) {
             return voidType;
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -103,10 +103,10 @@
         }
 
         @Override
-        public boolean matches(TypeMirror actualType) {
+        public boolean matches(VariableElement variable) {
             boolean found = false;
             for (TypeMirror specType : getAllowedTypes()) {
-                if (ElementUtils.isAssignable(actualType, specType)) {
+                if (ElementUtils.isAssignable(variable.asType(), specType)) {
                     found = true;
                     break;
                 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -36,9 +36,11 @@
 public class ExecutableTypeMethodParser extends NodeMethodParser<ExecutableTypeData> {
 
     private final List<TypeMirror> frameTypes;
+    private final NodeChildData child;
 
-    public ExecutableTypeMethodParser(ProcessorContext context, NodeData node, List<TypeMirror> frameTypes) {
+    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);
@@ -54,9 +56,19 @@
         TypeSystemData typeSystem = getNode().getTypeSystem();
         List<TypeMirror> allowedTypes = typeSystem.getPrimitiveTypeMirrors();
         Set<String> allowedIdentifiers = typeSystem.getTypeIdentifiers();
-        for (ParameterSpec originalSpec : requiredSpecs) {
-            spec.addRequired(new ParameterSpec(originalSpec, allowedTypes, allowedIdentifiers));
+
+        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);
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +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 GuardParser extends NodeMethodParser<GuardData> {
-
-    private final GuardExpression expression;
-    private final TemplateMethod guardedMethod;
-
-    public GuardParser(ProcessorContext context, NodeData node, TemplateMethod compatibleSource, GuardExpression expression) {
-        super(context, node);
-        this.expression = expression;
-        this.guardedMethod = compatibleSource;
-        getParser().setEmitErrors(false);
-        setParseNullOnError(false);
-    }
-
-    @Override
-    protected ParameterSpec createValueParameterSpec(NodeExecutionData execution) {
-        return super.createValueParameterSpec(execution);
-    }
-
-    @Override
-    public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null);
-        spec.setIgnoreAdditionalSpecifications(true);
-        spec.getRequired().clear();
-
-        if (expression.getResolvedChildren() != null) {
-            for (NodeExecutionData execution : expression.getResolvedChildren()) {
-                List<Parameter> foundInGuardedMethod = guardedMethod.findByExecutionData(execution);
-                for (Parameter guardedParameter : foundInGuardedMethod) {
-                    spec.addRequired(createParameterSpec(guardedParameter));
-                }
-            }
-        } else {
-            for (Parameter parameter : guardedMethod.getRequiredParameters()) {
-                spec.addRequired(createParameterSpec(parameter));
-            }
-        }
-
-        return spec;
-    }
-
-    private ParameterSpec createParameterSpec(Parameter parameter) {
-        List<TypeMirror> typeMirrors = ElementUtils.getAssignableTypes(getContext(), parameter.getType());
-        Set<String> typeIds = new HashSet<>();
-        for (TypeMirror typeMirror : typeMirrors) {
-            typeIds.add(ElementUtils.getUniqueIdentifier(typeMirror));
-        }
-        if (parameter.getSpecification().isSignature()) {
-            typeIds.retainAll(getTypeSystem().getTypeIdentifiers());
-        }
-
-        return new ParameterSpec(parameter.getSpecification(), typeMirrors, typeIds);
-    }
-
-    @Override
-    protected List<TypeMirror> nodeTypeMirrors(NodeData nodeData) {
-        Set<TypeMirror> typeMirrors = new LinkedHashSet<>();
-        typeMirrors.addAll(nodeData.getTypeSystem().getPrimitiveTypeMirrors());
-        typeMirrors.addAll(nodeData.getTypeSystem().getBoxedTypeMirrors());
-        return new ArrayList<>(typeMirrors);
-    }
-
-    @Override
-    protected Set<String> nodeTypeIdentifiers(NodeData nodeData) {
-        return nodeData.getTypeSystem().getTypeIdentifiers();
-    }
-
-    @Override
-    protected ParameterSpec createReturnParameterSpec() {
-        return new ParameterSpec("returnType", getContext().getType(boolean.class));
-    }
-
-    @Override
-    public boolean isParsable(ExecutableElement method) {
-        return true;
-    }
-
-    @Override
-    public GuardData create(TemplateMethod method, boolean invalid) {
-        Implies impliesAnnotation = method.getMethod().getAnnotation(Implies.class);
-        String[] impliesExpressions = new String[0];
-        if (impliesAnnotation != null) {
-            impliesExpressions = impliesAnnotation.value();
-        }
-        List<GuardExpression> guardExpressions = new ArrayList<>();
-        for (String string : impliesExpressions) {
-            guardExpressions.add(new GuardExpression(string, false));
-        }
-        return new GuardData(method, guardExpressions);
-    }
-
-    @Override
-    public Class<? extends Annotation> getAnnotationType() {
-        return null;
-    }
-
-}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -30,6 +30,7 @@
 import javax.lang.model.type.*;
 
 import com.oracle.truffle.dsl.processor.java.*;
+import com.oracle.truffle.dsl.processor.java.model.*;
 import com.oracle.truffle.dsl.processor.model.*;
 
 public final class MethodSpecParser {
@@ -76,18 +77,13 @@
 
         String id = method.getSimpleName().toString();
         TypeMirror returnType = method.getReturnType();
-        List<TypeMirror> parameterTypes = new ArrayList<>();
-        for (VariableElement var : method.getParameters()) {
-            parameterTypes.add(var.asType());
-        }
-
-        return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, parameterTypes);
+        return parseImpl(methodSpecification, naturalOrder, id, method, annotation, returnType, method.getParameters());
     }
 
     public TemplateMethod parseImpl(MethodSpec methodSpecification, int naturalOrder, String id, ExecutableElement method, AnnotationMirror annotation, TypeMirror returnType,
-                    List<TypeMirror> parameterTypes) {
+                    List<? extends VariableElement> parameterTypes) {
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
-        Parameter returnTypeMirror = matchParameter(returnTypeSpec, returnType, -1, -1);
+        Parameter returnTypeMirror = matchParameter(returnTypeSpec, new CodeVariableElement(returnType, "returnType"), -1, -1);
         if (returnTypeMirror == null) {
             if (emitErrors) {
                 TemplateMethod invalidMethod = new TemplateMethod(id, naturalOrder, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<Parameter> emptyList());
@@ -139,11 +135,11 @@
      * 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<TypeMirror> parameterTypes, boolean varArgs) {
+    private List<Parameter> parseParameters(MethodSpec spec, List<? extends VariableElement> parameterTypes, boolean varArgs) {
         List<Parameter> parsedRequired = null;
         int offset = 0;
         for (; offset <= parameterTypes.size(); offset++) {
-            List<TypeMirror> parameters = new ArrayList<>();
+            List<VariableElement> parameters = new ArrayList<>();
             parameters.addAll(parameterTypes.subList(offset, parameterTypes.size()));
             parsedRequired = parseParametersRequired(spec, parameters, varArgs);
             if (parsedRequired != null) {
@@ -158,7 +154,7 @@
         if (parsedRequired.isEmpty() && offset == 0) {
             offset = parameterTypes.size();
         }
-        List<TypeMirror> potentialOptionals = parameterTypes.subList(0, offset);
+        List<? extends VariableElement> potentialOptionals = parameterTypes.subList(0, offset);
         List<Parameter> parsedOptionals = parseParametersOptional(spec, potentialOptionals);
         if (parsedOptionals == null) {
             return null;
@@ -170,7 +166,7 @@
         return finalParameters;
     }
 
-    private List<Parameter> parseParametersOptional(MethodSpec spec, List<TypeMirror> types) {
+    private List<Parameter> parseParametersOptional(MethodSpec spec, List<? extends VariableElement> types) {
         List<Parameter> parsedParams = new ArrayList<>();
 
         int typeStartIndex = 0;
@@ -178,8 +174,8 @@
         outer: for (int specIndex = 0; specIndex < specifications.size(); specIndex++) {
             ParameterSpec specification = specifications.get(specIndex);
             for (int typeIndex = typeStartIndex; typeIndex < types.size(); typeIndex++) {
-                TypeMirror actualType = types.get(typeIndex);
-                Parameter optionalParam = matchParameter(specification, actualType, -1, -1);
+                VariableElement variable = types.get(typeIndex);
+                Parameter optionalParam = matchParameter(specification, variable, -1, -1);
                 if (optionalParam != null) {
                     parsedParams.add(optionalParam);
                     typeStartIndex = typeIndex + 1;
@@ -195,7 +191,7 @@
         return parsedParams;
     }
 
-    private List<Parameter> parseParametersRequired(MethodSpec spec, List<TypeMirror> types, boolean typeVarArgs) {
+    private List<Parameter> parseParametersRequired(MethodSpec spec, List<VariableElement> types, boolean typeVarArgs) {
         List<Parameter> parsedParams = new ArrayList<>();
         List<ParameterSpec> specifications = spec.getRequired();
         boolean specVarArgs = spec.isVariableRequiredParameters();
@@ -204,7 +200,7 @@
 
         ParameterSpec specification;
         while ((specification = nextSpecification(specifications, specificationIndex, specVarArgs)) != null) {
-            TypeMirror actualType = nextActualType(types, typeIndex, typeVarArgs);
+            VariableElement actualType = nextActualType(types, typeIndex, typeVarArgs);
             if (actualType == null) {
                 if (spec.isIgnoreAdditionalSpecifications()) {
                     break;
@@ -230,8 +226,18 @@
             specificationIndex++;
         }
 
+        // consume randomly ordered annotated parameters
+        VariableElement variable;
+        while ((variable = nextActualType(types, typeIndex, typeVarArgs)) != null) {
+            Parameter matchedParamter = matchAnnotatedParameter(spec, variable);
+            if (matchedParamter == null) {
+                break;
+            }
+            parsedParams.add(matchedParamter);
+            typeIndex++;
+        }
+
         if (typeIndex < types.size()) {
-            // additional types available
             if (spec.isIgnoreAdditionalParameters()) {
                 return parsedParams;
             } else {
@@ -242,6 +248,19 @@
         return parsedParams;
     }
 
+    private Parameter matchAnnotatedParameter(MethodSpec spec, VariableElement variable) {
+        for (ParameterSpec parameterSpec : spec.getAnnotations()) {
+            if (parameterSpec.matches(variable)) {
+                Parameter matchedParameter = matchParameter(parameterSpec, variable, -1, -1);
+                if (matchedParameter != null) {
+                    matchedParameter.setLocalName(variable.getSimpleName().toString());
+                    return matchedParameter;
+                }
+            }
+        }
+        return null;
+    }
+
     private static ParameterSpec nextSpecification(List<ParameterSpec> specifications, int specIndex, boolean varArgs) {
         if (varArgs && specIndex >= specifications.size() - 1 && !specifications.isEmpty()) {
             return specifications.get(specifications.size() - 1);
@@ -252,12 +271,12 @@
         }
     }
 
-    private static TypeMirror nextActualType(List<TypeMirror> types, int typeIndex, boolean varArgs) {
+    private static VariableElement nextActualType(List<VariableElement> types, int typeIndex, boolean varArgs) {
         if (varArgs && typeIndex >= types.size() - 1 && !types.isEmpty()) {
             // unpack varargs array argument
-            TypeMirror actualType = types.get(types.size() - 1);
-            if (actualType.getKind() == TypeKind.ARRAY) {
-                actualType = ((ArrayType) actualType).getComponentType();
+            VariableElement actualType = types.get(types.size() - 1);
+            if (actualType.asType().getKind() == TypeKind.ARRAY) {
+                actualType = new CodeVariableElement(((ArrayType) actualType.asType()).getComponentType(), actualType.getSimpleName().toString());
             }
             return actualType;
         } else if (typeIndex < types.size()) {
@@ -267,21 +286,21 @@
         }
     }
 
-    private Parameter matchParameter(ParameterSpec specification, TypeMirror mirror, int specificationIndex, int varArgsIndex) {
-        TypeMirror resolvedType = mirror;
+    private Parameter matchParameter(ParameterSpec specification, VariableElement variable, int specificationIndex, int varArgsIndex) {
+        TypeMirror resolvedType = variable.asType();
         if (hasError(resolvedType)) {
             return null;
         }
 
-        if (!specification.matches(resolvedType)) {
+        if (!specification.matches(variable)) {
             return null;
         }
 
         TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType);
         if (resolvedTypeData != null) {
-            return new Parameter(specification, resolvedTypeData, specificationIndex, varArgsIndex);
+            return new Parameter(specification, resolvedTypeData, variable, specificationIndex, varArgsIndex);
         } else {
-            return new Parameter(specification, resolvedType, 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	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -89,7 +89,7 @@
         }
 
         for (NodeExecutionData execution : getNode().getChildExecutions()) {
-            if (breakName != null && execution.getShortCircuitId().equals(breakName)) {
+            if (breakName != null && execution.getIndexedName().equals(breakName)) {
                 break;
             }
 
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -30,11 +30,15 @@
 import javax.lang.model.util.*;
 import javax.tools.Diagnostic.Kind;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.dsl.processor.*;
+import com.oracle.truffle.dsl.processor.expression.*;
 import com.oracle.truffle.dsl.processor.java.*;
 import com.oracle.truffle.dsl.processor.java.compiler.*;
+import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
+import com.oracle.truffle.dsl.processor.java.model.*;
 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;
@@ -98,7 +102,8 @@
         } catch (CompileErrorException e) {
             throw e;
         } catch (Throwable e) {
-            throw new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e);
+            e.addSuppressed(new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e));
+            throw e;
         }
         if (node == null && !enclosedNodes.isEmpty()) {
             node = new NodeData(context, rootType);
@@ -133,12 +138,14 @@
         }
 
         NodeData node = parseNodeData(templateType, lookupTypes);
+        if (node.hasErrors()) {
+            return node;
+        }
 
-        node.getAssumptions().addAll(parseAssumptions(lookupTypes));
         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, context.getFrameTypes()).parse(members)));
+        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, null, context.getFrameTypes()).parse(members)));
 
         initializeExecutableTypes(node);
         initializeImportGuards(node, lookupTypes, members);
@@ -174,8 +181,10 @@
         return node;
     }
 
-    private ArrayList<Element> loadMembers(TypeElement templateType) {
-        return new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
+    private List<Element> loadMembers(TypeElement templateType) {
+        List<Element> members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
+
+        return members;
     }
 
     private boolean containsSpecializations(List<Element> elements) {
@@ -191,7 +200,7 @@
 
     private void initializeImportGuards(NodeData node, List<TypeElement> lookupTypes, List<Element> elements) {
         for (TypeElement lookupType : lookupTypes) {
-            AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportGuards.class);
+            AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportStatic.class);
             if (importAnnotation == null) {
                 continue;
             }
@@ -206,29 +215,44 @@
                     node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' is not a declared type.", ElementUtils.getQualifiedName(importGuardClass));
                     continue;
                 }
+
                 TypeElement typeElement = ElementUtils.fromTypeMirror(importGuardClass);
-
-                // hack to reload type is necessary for incremental compiling in eclipse.
-                // otherwise methods inside of import guard types are just not found.
-                typeElement = ElementUtils.fromTypeMirror(context.reloadType(typeElement.asType()));
-
                 if (typeElement.getEnclosingElement().getKind().isClass() && !typeElement.getModifiers().contains(Modifier.PUBLIC)) {
                     node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' must be public.", ElementUtils.getQualifiedName(importGuardClass));
                     continue;
                 }
-
-                List<? extends ExecutableElement> importMethods = ElementFilter.methodsIn(processingEnv.getElementUtils().getAllMembers(typeElement));
-
-                for (ExecutableElement importMethod : importMethods) {
-                    if (!importMethod.getModifiers().contains(Modifier.PUBLIC) || !importMethod.getModifiers().contains(Modifier.STATIC)) {
-                        continue;
-                    }
-                    elements.add(importMethod);
-                }
+                elements.addAll(importPublicStaticMembers(typeElement, false));
             }
         }
     }
 
+    private List<? extends Element> importPublicStaticMembers(TypeElement importGuardClass, boolean includeConstructors) {
+        // hack to reload type is necessary for incremental compiling in eclipse.
+        // otherwise methods inside of import guard types are just not found.
+        TypeElement typeElement = ElementUtils.fromTypeMirror(context.reloadType(importGuardClass.asType()));
+
+        List<Element> members = new ArrayList<>();
+        for (Element importElement : processingEnv.getElementUtils().getAllMembers(typeElement)) {
+            if (!importElement.getModifiers().contains(Modifier.PUBLIC)) {
+                continue;
+            }
+
+            if (includeConstructors && importElement.getKind() == ElementKind.CONSTRUCTOR) {
+                members.add(importElement);
+            }
+
+            if (!importElement.getModifiers().contains(Modifier.STATIC)) {
+                continue;
+            }
+
+            ElementKind kind = importElement.getKind();
+            if (kind.isField() || kind == ElementKind.METHOD) {
+                members.add(importElement);
+            }
+        }
+        return members;
+    }
+
     private NodeData parseNodeData(TypeElement templateType, List<TypeElement> typeHierarchy) {
         AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
         if (typeSystemMirror == null) {
@@ -255,24 +279,6 @@
 
     }
 
-    private List<String> parseAssumptions(List<TypeElement> typeHierarchy) {
-        List<String> assumptionsList = new ArrayList<>();
-        for (int i = typeHierarchy.size() - 1; i >= 0; i--) {
-            TypeElement type = typeHierarchy.get(i);
-            AnnotationMirror assumptions = ElementUtils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class);
-            if (assumptions != null) {
-                List<String> assumptionStrings = ElementUtils.getAnnotationValueList(String.class, assumptions, "value");
-                for (String string : assumptionStrings) {
-                    if (assumptionsList.contains(string)) {
-                        assumptionsList.remove(string);
-                    }
-                    assumptionsList.add(string);
-                }
-            }
-        }
-        return assumptionsList;
-    }
-
     private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) {
         Set<String> names = new HashSet<>();
 
@@ -283,7 +289,7 @@
             }
             if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) {
                 String name = field.getSimpleName().toString();
-                fields.add(new NodeFieldData(field, null, field.asType(), name, false));
+                fields.add(new NodeFieldData(field, null, field, false));
                 names.add(name);
             }
         }
@@ -298,7 +304,7 @@
                 String name = ElementUtils.firstLetterLowerCase(ElementUtils.getAnnotationValue(String.class, mirror, "name"));
                 TypeMirror type = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "type");
 
-                NodeFieldData field = new NodeFieldData(typeElement, mirror, type, name, true);
+                NodeFieldData field = new NodeFieldData(typeElement, mirror, new CodeVariableElement(type, name), true);
                 if (name.isEmpty()) {
                     field.addError(ElementUtils.getAnnotationValue(mirror, "name"), "Field name cannot be empty.");
                 } else if (names.contains(name)) {
@@ -396,46 +402,6 @@
             }
         }
 
-        for (NodeChildData child : filteredChildren) {
-            List<String> executeWithStrings = ElementUtils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
-            AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
-            List<NodeChildData> executeWith = new ArrayList<>();
-            for (String executeWithString : executeWithStrings) {
-
-                if (child.getName().equals(executeWithString)) {
-                    child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString);
-                    continue;
-                }
-
-                NodeChildData found = null;
-                boolean before = true;
-                for (NodeChildData resolveChild : filteredChildren) {
-                    if (resolveChild == child) {
-                        before = false;
-                        continue;
-                    }
-                    if (resolveChild.getName().equals(executeWithString)) {
-                        found = resolveChild;
-                        break;
-                    }
-                }
-
-                if (found == null) {
-                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString);
-                    continue;
-                } else if (!before) {
-                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString,
-                                    executeWithString);
-                    continue;
-                }
-                executeWith.add(found);
-            }
-            child.setExecuteWith(executeWith);
-            if (child.getNodeData() == null) {
-                continue;
-            }
-        }
-
         return filteredChildren;
     }
 
@@ -466,6 +432,7 @@
             }
         }
 
+        TypeMirror cacheAnnotation = context.getType(Cached.class);
         List<TypeMirror> frameTypes = context.getFrameTypes();
         // pre-parse specializations to find signature size
         for (ExecutableElement method : methods) {
@@ -473,10 +440,10 @@
             if (mirror == null) {
                 continue;
             }
-
             int currentArgumentIndex = 0;
             boolean skipShortCircuit = false;
             outer: for (VariableElement var : method.getParameters()) {
+
                 TypeMirror type = var.asType();
                 if (currentArgumentIndex == 0) {
                     // skip optionals
@@ -486,13 +453,18 @@
                         }
                     }
                 }
+
+                if (ElementUtils.findAnnotationMirror(var.getAnnotationMirrors(), cacheAnnotation) != null) {
+                    continue outer;
+                }
+
                 int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1;
                 if (childIndex == -1) {
                     continue;
                 }
                 if (!skipShortCircuit) {
                     NodeChildData child = children.get(childIndex);
-                    if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentIndex - childIndex))) {
+                    if (shortCircuits.contains(NodeExecutionData.createIndexedName(child, currentArgumentIndex - childIndex))) {
                         skipShortCircuit = true;
                         continue;
                     }
@@ -519,7 +491,7 @@
             }
             int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1;
             NodeChildData child = children.get(childIndex);
-            boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex));
+            boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex));
             executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit));
         }
         return executions;
@@ -536,16 +508,11 @@
 
             Parameter frame = execute.getFrame();
             TypeMirror resolvedFrameType;
-            if (frame == null) {
-                resolvedFrameType = node.getTypeSystem().getVoidType().getPrimitiveType();
-            } else {
+            if (frame != null) {
                 resolvedFrameType = frame.getType();
-            }
-
-            if (frameType == null) {
-                frameType = resolvedFrameType;
-            } else {
-                if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
+                if (frameType == null) {
+                    frameType = resolvedFrameType;
+                } else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
                     // found inconsistent frame types
                     inconsistentFrameTypes.add(ElementUtils.getSimpleName(frameType));
                     inconsistentFrameTypes.add(ElementUtils.getSimpleName(resolvedFrameType));
@@ -558,6 +525,10 @@
             Collections.sort(inconsistentFrameTypesList);
             node.addError("Invalid inconsistent frame types %s found for the declared execute methods. The frame type must be identical for all execute methods.", inconsistentFrameTypesList);
         }
+        if (frameType == null) {
+            frameType = context.getType(void.class);
+        }
+
         node.setFrameType(frameType);
 
         int totalGenericCount = 0;
@@ -627,9 +598,11 @@
     }
 
     private void initializeChildren(NodeData node) {
+        initializeExecuteWith(node);
+
         for (NodeChildData child : node.getChildren()) {
             TypeMirror nodeType = child.getNodeType();
-            NodeData fieldNodeData = parseChildNodeData(node, ElementUtils.fromTypeMirror(nodeType));
+            NodeData fieldNodeData = parseChildNodeData(node, child, ElementUtils.fromTypeMirror(nodeType));
 
             child.setNode(fieldNodeData);
             if (fieldNodeData == null || fieldNodeData.hasErrors()) {
@@ -649,7 +622,44 @@
         }
     }
 
-    private NodeData parseChildNodeData(NodeData parentNode, TypeElement originalTemplateType) {
+    private static void initializeExecuteWith(NodeData node) {
+        for (NodeChildData child : node.getChildren()) {
+            List<String> executeWithStrings = ElementUtils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
+            AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
+            List<NodeExecutionData> executeWith = new ArrayList<>();
+            for (String executeWithString : executeWithStrings) {
+                if (child.getName().equals(executeWithString)) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString);
+                    continue;
+                }
+                NodeExecutionData found = null;
+                boolean before = true;
+                for (NodeExecutionData resolveChild : node.getChildExecutions()) {
+                    if (resolveChild.getChild() == child) {
+                        before = false;
+                        continue;
+                    }
+                    if (resolveChild.getIndexedName().equals(executeWithString)) {
+                        found = resolveChild;
+                        break;
+                    }
+                }
+
+                if (found == null) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString);
+                    continue;
+                } else if (!before) {
+                    child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString,
+                                    executeWithString);
+                    continue;
+                }
+                executeWith.add(found);
+            }
+            child.setExecuteWith(executeWith);
+        }
+    }
+
+    private NodeData parseChildNodeData(NodeData parentNode, NodeChildData child, TypeElement originalTemplateType) {
         TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
 
         if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
@@ -666,8 +676,10 @@
         // Declaration order is not required for child nodes.
         List<? extends Element> members = processingEnv.getElementUtils().getAllMembers(templateType);
         NodeData node = parseNodeData(templateType, lookupTypes);
-
-        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, createAllowedChildFrameTypes(parentNode)).parse(members)));
+        if (node.hasErrors()) {
+            return node;
+        }
+        node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, child, createAllowedChildFrameTypes(parentNode)).parse(members)));
         node.setFrameType(parentNode.getFrameType());
         return node;
     }
@@ -687,31 +699,29 @@
             return;
         }
 
-        initializeGuards(elements, node);
+        initializeExpressions(elements, node);
+
+        if (node.hasErrors()) {
+            return;
+        }
+
         initializeGeneric(node);
         initializeUninitialized(node);
         initializeOrder(node);
         initializePolymorphism(node); // requires specializations
         initializeReachability(node);
         initializeContains(node);
-
-        if (!node.hasErrors() && !node.getTypeSystem().getOptions().useNewLayout()) {
-            initializeExceptions(node);
-        }
         resolveContains(node);
 
-        if (node.getTypeSystem().getOptions().useNewLayout()) {
-            List<SpecializationData> specializations = node.getSpecializations();
-            for (SpecializationData cur : specializations) {
-                for (SpecializationData child : specializations) {
-                    if (child != null && child != cur && child.getContains().contains(cur)) {
-                        cur.getExcludedBy().add(child);
-                    }
+        List<SpecializationData> specializations = node.getSpecializations();
+        for (SpecializationData cur : specializations) {
+            for (SpecializationData contained : cur.getContains()) {
+                if (contained != cur) {
+                    contained.getExcludedBy().add(cur);
                 }
             }
         }
 
-        // verify specialization parameter length
         initializeSpecializationIdsWithMethodNames(node.getSpecializations());
     }
 
@@ -763,40 +773,6 @@
         }
     }
 
-    private static void initializeExceptions(NodeData node) {
-        List<SpecializationData> specializations = node.getSpecializations();
-
-        for (int i = 0; i < specializations.size(); i++) {
-            SpecializationData cur = specializations.get(i);
-            if (cur.getExceptions().isEmpty()) {
-                continue;
-            }
-            SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null;
-
-            if (!cur.isContainedBy(next)) {
-                next.addError("This specialiation is not a valid exceptional rewrite target for %s. To fix this make %s compatible to %s or remove the exceptional rewrite.",
-                                cur.createReferenceName(), next != null ? next.createReferenceName() : "-", cur.createReferenceName());
-                continue;
-            }
-            Set<SpecializationData> nextContains = next != null ? next.getContains() : Collections.<SpecializationData> emptySet();
-            if (!nextContains.contains(cur)) {
-                nextContains.add(cur);
-            }
-        }
-
-        for (SpecializationData cur : specializations) {
-            if (cur.getExceptions().isEmpty()) {
-                continue;
-            }
-            for (SpecializationData child : specializations) {
-                if (child != null && child != cur && child.getContains().contains(cur)) {
-                    cur.getExcludedBy().add(child);
-                }
-            }
-        }
-
-    }
-
     private static void initializeContains(NodeData node) {
         for (SpecializationData specialization : node.getSpecializations()) {
             Set<SpecializationData> resolvedSpecializations = specialization.getContains();
@@ -810,14 +786,10 @@
                     AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains");
                     specialization.addError(value, "The referenced specialization '%s' could not be found.", includeName);
                 } else {
-                    if (!foundSpecialization.isContainedBy(specialization)) {
+                    if (foundSpecialization.compareTo(specialization) > 0) {
                         AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains");
                         if (foundSpecialization.compareTo(specialization) > 0) {
                             specialization.addError(value, "The contained specialization '%s' must be declared before the containing specialization.", includeName);
-                        } else {
-                            specialization.addError(value,
-                                            "The contained specialization '%s' is not fully compatible. The contained specialization must be strictly more generic than the containing one.",
-                                            includeName);
                         }
 
                     }
@@ -964,74 +936,193 @@
         return changed;
     }
 
-    private void initializeGuards(List<? extends Element> elements, NodeData node) {
-        Map<String, List<ExecutableElement>> potentialGuards = new HashMap<>();
-        for (SpecializationData specialization : node.getSpecializations()) {
-            for (GuardExpression exp : specialization.getGuards()) {
-                potentialGuards.put(exp.getGuardName(), null);
-            }
+    private void initializeExpressions(List<? extends Element> elements, NodeData node) {
+        List<Element> members = filterNotAccessibleElements(node.getTemplateType(), elements);
+
+        List<VariableElement> fields = new ArrayList<>();
+        for (NodeFieldData field : node.getFields()) {
+            fields.add(field.getVariable());
         }
 
-        TypeMirror booleanType = context.getType(boolean.class);
-        for (ExecutableElement potentialGuard : ElementFilter.methodsIn(elements)) {
-            if (potentialGuard.getModifiers().contains(Modifier.PRIVATE)) {
-                continue;
-            }
-            String methodName = potentialGuard.getSimpleName().toString();
-            if (!potentialGuards.containsKey(methodName)) {
+        for (SpecializationData specialization : node.getSpecializations()) {
+            if (specialization.getMethod() == null) {
                 continue;
             }
 
-            if (!ElementUtils.typeEquals(potentialGuard.getReturnType(), booleanType)) {
+            List<Element> specializationMembers = new ArrayList<>(members.size() + specialization.getParameters().size() + fields.size());
+            for (Parameter p : specialization.getParameters()) {
+                specializationMembers.add(p.getVariableElement());
+            }
+            specializationMembers.addAll(fields);
+            specializationMembers.addAll(members);
+            DSLExpressionResolver resolver = new DSLExpressionResolver(context, specializationMembers);
+
+            initializeCaches(specialization, resolver);
+            initializeGuards(specialization, resolver);
+            if (specialization.hasErrors()) {
                 continue;
             }
+            initializeLimit(specialization, resolver);
+            initializeAssumptions(specialization, resolver);
+        }
+    }
+
+    private void initializeAssumptions(SpecializationData specialization, DSLExpressionResolver resolver) {
+        final DeclaredType assumptionType = context.getDeclaredType(Assumption.class);
+        final TypeMirror assumptionArrayType = new ArrayCodeTypeMirror(assumptionType);
+        final List<String> assumptionDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions");
+        List<AssumptionExpression> assumptionExpressions = new ArrayList<>();
+        int assumptionId = 0;
+        for (String assumption : assumptionDefinitions) {
+            AssumptionExpression assumptionExpression;
+            DSLExpression expression = null;
+            try {
+                expression = DSLExpression.parse(assumption);
+                expression.accept(resolver);
+                assumptionExpression = new AssumptionExpression(specialization, expression, "assumption" + assumptionId);
+                if (!ElementUtils.isAssignable(expression.getResolvedType(), assumptionType) && !ElementUtils.isAssignable(expression.getResolvedType(), assumptionArrayType)) {
+                    assumptionExpression.addError("Incompatible return type %s. Assumptions must be assignable to %s or %s.", ElementUtils.getSimpleName(expression.getResolvedType()),
+                                    ElementUtils.getSimpleName(assumptionType), ElementUtils.getSimpleName(assumptionArrayType));
+                }
+                if (specialization.isDynamicParameterBound(expression)) {
+                    specialization.addError("Assumption expressions must not bind dynamic parameter values.");
+                }
+            } catch (InvalidExpressionException e) {
+                assumptionExpression = new AssumptionExpression(specialization, null, "assumption" + assumptionId);
+                assumptionExpression.addError("Error parsing expression '%s': %s", assumption, e.getMessage());
+            }
+            assumptionExpressions.add(assumptionExpression);
+        }
+        specialization.setAssumptionExpressions(assumptionExpressions);
+    }
+
+    private void initializeLimit(SpecializationData specialization, DSLExpressionResolver resolver) {
+        AnnotationValue annotationValue = ElementUtils.getAnnotationValue(specialization.getMessageAnnotation(), "limit");
+
+        String limitValue;
+        if (annotationValue == null) {
+            limitValue = "";
+        } else {
+            limitValue = (String) annotationValue.getValue();
+        }
+        if (limitValue.isEmpty()) {
+            limitValue = "3";
+        } else if (!specialization.hasMultipleInstances()) {
+            specialization.addWarning(annotationValue, "The limit expression has no effect. Multiple specialization instantiations are impossible for this specialization.");
+            return;
+        }
+
+        TypeMirror expectedType = context.getType(int.class);
+        try {
+            DSLExpression expression = DSLExpression.parse(limitValue);
+            expression.accept(resolver);
+            if (!ElementUtils.typeEquals(expression.getResolvedType(), expectedType)) {
+                specialization.addError(annotationValue, "Incompatible return type %s. Limit expressions must return %s.", ElementUtils.getSimpleName(expression.getResolvedType()),
+                                ElementUtils.getSimpleName(expectedType));
+            }
+            if (specialization.isDynamicParameterBound(expression)) {
+                specialization.addError(annotationValue, "Limit expressions must not bind dynamic parameter values.");
+            }
 
-            List<ExecutableElement> potentialMethods = potentialGuards.get(methodName);
-            if (potentialMethods == null) {
-                potentialMethods = new ArrayList<>();
-                potentialGuards.put(methodName, potentialMethods);
+            specialization.setLimitExpression(expression);
+        } catch (InvalidExpressionException e) {
+            specialization.addError(annotationValue, "Error parsing expression '%s': %s", limitValue, e.getMessage());
+        }
+    }
+
+    private void initializeCaches(SpecializationData specialization, DSLExpressionResolver resolver) {
+        TypeMirror cacheMirror = context.getType(Cached.class);
+        List<CacheExpression> expressions = new ArrayList<>();
+        for (Parameter parameter : specialization.getParameters()) {
+            AnnotationMirror annotationMirror = ElementUtils.findAnnotationMirror(parameter.getVariableElement().getAnnotationMirrors(), cacheMirror);
+            if (annotationMirror != null) {
+                String initializer = ElementUtils.getAnnotationValue(String.class, annotationMirror, "value");
+
+                TypeMirror parameterType = parameter.getType();
+
+                DSLExpressionResolver localResolver = resolver;
+                if (parameterType.getKind() == TypeKind.DECLARED) {
+                    localResolver = localResolver.copy(importPublicStaticMembers(ElementUtils.fromTypeMirror(parameterType), true));
+                }
+
+                CacheExpression cacheExpression;
+                DSLExpression expression = null;
+                try {
+                    expression = DSLExpression.parse(initializer);
+                    expression.accept(localResolver);
+                    cacheExpression = new CacheExpression(parameter, annotationMirror, expression);
+                    if (!ElementUtils.typeEquals(expression.getResolvedType(), parameter.getType())) {
+                        cacheExpression.addError("Incompatible return type %s. The expression type must be equal to the parameter type %s.", ElementUtils.getSimpleName(expression.getResolvedType()),
+                                        ElementUtils.getSimpleName(parameter.getType()));
+                    }
+                } catch (InvalidExpressionException e) {
+                    cacheExpression = new CacheExpression(parameter, annotationMirror, null);
+                    cacheExpression.addError("Error parsing expression '%s': %s", initializer, e.getMessage());
+                }
+                expressions.add(cacheExpression);
             }
-            potentialMethods.add(potentialGuard);
+        }
+        specialization.setCaches(expressions);
+
+        if (specialization.hasErrors()) {
+            return;
         }
 
-        for (SpecializationData specialization : node.getSpecializations()) {
-            for (GuardExpression exp : specialization.getGuards()) {
-                resolveGuardExpression(node, specialization, potentialGuards, exp);
+        // verify that cache expressions are bound in the correct order.
+        for (int i = 0; i < expressions.size(); i++) {
+            CacheExpression currentExpression = expressions.get(i);
+            Set<VariableElement> boundVariables = currentExpression.getExpression().findBoundVariableElements();
+            for (int j = i + 1; j < expressions.size(); j++) {
+                CacheExpression boundExpression = expressions.get(j);
+                if (boundVariables.contains(boundExpression.getParameter().getVariableElement())) {
+                    currentExpression.addError("The initializer expression of parameter '%s' binds unitialized parameter '%s. Reorder the parameters to resolve the problem.",
+                                    currentExpression.getParameter().getLocalName(), boundExpression.getParameter().getLocalName());
+                    break;
+                }
             }
         }
     }
 
-    private void resolveGuardExpression(NodeData node, TemplateMethod source, Map<String, List<ExecutableElement>> guards, GuardExpression expression) {
-        List<ExecutableElement> availableGuards = guards.get(expression.getGuardName());
-        if (availableGuards == null) {
-            source.addError("No compatible guard with method name '%s' found.", expression.getGuardName());
-            return;
+    private void initializeGuards(SpecializationData specialization, DSLExpressionResolver resolver) {
+        final TypeMirror booleanType = context.getType(boolean.class);
+        List<String> guardDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
+        List<GuardExpression> guardExpressions = new ArrayList<>();
+        for (String guard : guardDefinitions) {
+            GuardExpression guardExpression;
+            DSLExpression expression = null;
+            try {
+                expression = DSLExpression.parse(guard);
+                expression.accept(resolver);
+                guardExpression = new GuardExpression(specialization, expression);
+                if (!ElementUtils.typeEquals(expression.getResolvedType(), booleanType)) {
+                    guardExpression.addError("Incompatible return type %s. Guards must return %s.", ElementUtils.getSimpleName(expression.getResolvedType()), ElementUtils.getSimpleName(booleanType));
+                }
+            } catch (InvalidExpressionException e) {
+                guardExpression = new GuardExpression(specialization, null);
+                guardExpression.addError("Error parsing expression '%s': %s", guard, e.getMessage());
+            }
+            guardExpressions.add(guardExpression);
         }
+        specialization.setGuards(guardExpressions);
+    }
 
-        String[] childNames = expression.getChildNames();
-        if (childNames != null) {
-            NodeExecutionData[] resolvedExecutions = new NodeExecutionData[childNames.length];
-            for (int i = 0; i < childNames.length; i++) {
-                String childName = childNames[i];
-                NodeExecutionData execution = node.findExecutionByExpression(childName);
-                if (execution == null) {
-                    source.addError("Guard parameter '%s' for guard '%s' could not be mapped to a declared child node.", childName, expression.getGuardName());
-                    return;
+    private static List<Element> filterNotAccessibleElements(TypeElement templateType, List<? extends Element> elements) {
+        String packageName = ElementUtils.getPackageName(templateType);
+        List<Element> filteredElements = new ArrayList<>(elements);
+        for (Element element : elements) {
+            Modifier visibility = ElementUtils.getVisibility(element.getModifiers());
+            if (visibility == Modifier.PRIVATE) {
+                continue;
+            } else if (visibility == null) {
+                String elementPackageName = ElementUtils.getPackageName(element.getEnclosingElement().asType());
+                if (!Objects.equals(packageName, elementPackageName) && !elementPackageName.equals("java.lang")) {
+                    continue;
                 }
-                resolvedExecutions[i] = execution;
             }
-            expression.setResolvedChildren(resolvedExecutions);
+
+            filteredElements.add(element);
         }
-
-        GuardParser parser = new GuardParser(context, node, source, expression);
-        List<GuardData> matchingGuards = parser.parse(availableGuards);
-        if (!matchingGuards.isEmpty() && matchingGuards.get(0) != null) {
-            expression.setResolvedGuard(matchingGuards.get(0));
-        } else {
-            MethodSpec spec = parser.createSpecification(source.getMethod(), source.getMarkerAnnotation());
-            spec.applyTypeDefinitions("types");
-            source.addError("No guard with name '%s' matched the required signature. Expected signature: %n%s", expression.getGuardName(), spec.toSignatureString("guard"));
-        }
+        return filteredElements;
     }
 
     private void initializeGeneric(final NodeData node) {
@@ -1068,10 +1159,10 @@
         GenericParser parser = new GenericParser(context, node);
         MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null);
 
-        List<TypeMirror> parameterTypes = new ArrayList<>();
+        List<VariableElement> parameterTypes = new ArrayList<>();
         int signatureIndex = 1;
         for (ParameterSpec spec : specification.getRequired()) {
-            parameterTypes.add(createGenericType(spec, node.getSpecializations(), signatureIndex));
+            parameterTypes.add(new CodeVariableElement(createGenericType(spec, node.getSpecializations(), signatureIndex), "arg" + signatureIndex));
             if (spec.isSignature()) {
                 signatureIndex++;
             }
@@ -1196,7 +1287,7 @@
                 continue;
             }
             shortCircuitExecutions.add(execution);
-            String valueName = execution.getShortCircuitId();
+            String valueName = execution.getIndexedName();
             List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
 
             if (availableCircuits == null || availableCircuits.isEmpty()) {
@@ -1252,7 +1343,7 @@
             List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size());
 
             for (NodeExecutionData shortCircuit : shortCircuitExecutions) {
-                List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId());
+                List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getIndexedName());
 
                 ShortCircuitData genericShortCircuit = null;
                 ShortCircuitData compatibleShortCircuit = null;
@@ -1392,62 +1483,22 @@
         }
     }
 
-    private void verifyConstructors(NodeData nodeData) {
-        if (nodeData.getTypeSystem().getOptions().useNewLayout()) {
-            List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeData.getTemplateType().getEnclosedElements());
-            if (constructors.isEmpty()) {
-                return;
-            }
-
-            boolean oneNonPrivate = false;
-            for (ExecutableElement constructor : constructors) {
-                if (ElementUtils.getVisibility(constructor.getModifiers()) != Modifier.PRIVATE) {
-                    oneNonPrivate = true;
-                    break;
-                }
-            }
-            if (!oneNonPrivate && !nodeData.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) {
-                nodeData.addError("At least one constructor must be non-private.");
-            }
-            return;
-        }
-        if (!nodeData.needsRewrites(context)) {
-            // no specialization constructor is needed if the node never rewrites.
+    private static void verifyConstructors(NodeData nodeData) {
+        List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeData.getTemplateType().getEnclosedElements());
+        if (constructors.isEmpty()) {
             return;
         }
 
-        TypeElement type = ElementUtils.fromTypeMirror(nodeData.getNodeType());
-        List<ExecutableElement> constructors = ElementFilter.constructorsIn(type.getEnclosedElements());
-
-        boolean parametersFound = false;
+        boolean oneNonPrivate = false;
         for (ExecutableElement constructor : constructors) {
-            if (!constructor.getParameters().isEmpty() && !isSourceSectionConstructor(context, constructor)) {
-                parametersFound = true;
+            if (ElementUtils.getVisibility(constructor.getModifiers()) != Modifier.PRIVATE) {
+                oneNonPrivate = true;
+                break;
             }
         }
-        if (!parametersFound) {
-            return;
+        if (!oneNonPrivate && !nodeData.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) {
+            nodeData.addError("At least one constructor must be non-private.");
         }
-        for (ExecutableElement e : constructors) {
-            if (e.getParameters().size() == 1) {
-                TypeMirror firstArg = e.getParameters().get(0).asType();
-                if (ElementUtils.typeEquals(firstArg, nodeData.getNodeType())) {
-                    if (e.getModifiers().contains(Modifier.PRIVATE)) {
-                        nodeData.addError("The specialization constructor must not be private.");
-                    } else if (constructors.size() <= 1) {
-                        nodeData.addError("The specialization constructor must not be the only constructor. The definition of an alternative constructor is required.");
-                    }
-                    return;
-                }
-            }
-        }
-
-        // not found
-        nodeData.addError("Specialization constructor '%s(%s previousNode) { this(...); }' is required.", ElementUtils.getSimpleName(type), ElementUtils.getSimpleName(type));
-    }
-
-    public static boolean isSourceSectionConstructor(ProcessorContext context, ExecutableElement constructor) {
-        return constructor.getParameters().size() == 1 && ElementUtils.typeEquals(constructor.getParameters().get(0).asType(), context.getTruffleTypes().getSourceSection());
     }
 
     private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ShortCircuitParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ShortCircuitParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -42,7 +42,7 @@
         shortCircuitValues = new HashSet<>();
         for (NodeExecutionData execution : node.getChildExecutions()) {
             if (execution.isShortCircuit()) {
-                shortCircuitValues.add(execution.getShortCircuitId());
+                shortCircuitValues.add(execution.getIndexedName());
             }
         }
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java	Thu Feb 12 04:01:46 2015 +0100
@@ -24,10 +24,6 @@
 
 import java.util.*;
 
-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.*;
 import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature;
 
@@ -37,7 +33,6 @@
  */
 public final class SpecializationGroup {
 
-    private final List<String> assumptions;
     private final List<TypeGuard> typeGuards;
     private final List<GuardExpression> guards;
 
@@ -49,12 +44,10 @@
 
     private SpecializationGroup(SpecializationData data) {
         this.node = data.getNode();
-        this.assumptions = new ArrayList<>();
         this.typeGuards = new ArrayList<>();
         this.guards = new ArrayList<>();
         this.specialization = data;
 
-        this.assumptions.addAll(data.getAssumptions());
         TypeSignature sig = data.getTypeSignature();
         for (int i = 1; i < sig.size(); i++) {
             typeGuards.add(new TypeGuard(sig.get(i), i - 1));
@@ -62,9 +55,8 @@
         this.guards.addAll(data.getGuards());
     }
 
-    public SpecializationGroup(List<SpecializationGroup> children, List<String> assumptionMatches, List<TypeGuard> typeGuardsMatches, List<GuardExpression> guardMatches) {
+    public SpecializationGroup(List<SpecializationGroup> children, List<TypeGuard> typeGuardsMatches, List<GuardExpression> guardMatches) {
         assert !children.isEmpty() : "children must not be empty";
-        this.assumptions = assumptionMatches;
         this.typeGuards = typeGuardsMatches;
         this.guards = guardMatches;
         this.node = children.get(0).node;
@@ -81,17 +73,8 @@
         return collectedGuards;
     }
 
-    public TypeGuard findTypeGuard(int signatureIndex) {
-        for (TypeGuard guard : typeGuards) {
-            if (guard.getSignatureIndex() == signatureIndex) {
-                return guard;
-            }
-        }
-        return null;
-    }
-
     public List<GuardExpression> findElseConnectableGuards() {
-        if (!getTypeGuards().isEmpty() || !getAssumptions().isEmpty()) {
+        if (!getTypeGuards().isEmpty()) {
             return Collections.emptyList();
         }
 
@@ -126,7 +109,7 @@
         }
 
         GuardExpression previousGuard = previous.getGuards().get(elseConnectedGuards.size());
-        if (guard.getResolvedGuard().getMethod().equals(previousGuard.getResolvedGuard().getMethod()) && guard.isNegated() != previousGuard.isNegated()) {
+        if (guard.equalsNegated(previousGuard)) {
             return guard;
         }
         return null;
@@ -146,10 +129,6 @@
         return parent;
     }
 
-    public List<String> getAssumptions() {
-        return assumptions;
-    }
-
     public List<TypeGuard> getTypeGuards() {
         return typeGuards;
     }
@@ -174,23 +153,12 @@
             return null;
         }
 
-        List<String> assumptionMatches = new ArrayList<>();
         List<TypeGuard> typeGuardsMatches = new ArrayList<>();
         List<GuardExpression> guardMatches = new ArrayList<>();
 
         SpecializationGroup first = groups.get(0);
         List<SpecializationGroup> others = groups.subList(1, groups.size());
 
-        outer: for (String assumption : first.assumptions) {
-            for (SpecializationGroup other : others) {
-                if (!other.assumptions.contains(assumption)) {
-                    // assumptions can be combined unordered
-                    continue outer;
-                }
-            }
-            assumptionMatches.add(assumption);
-        }
-
         outer: for (TypeGuard typeGuard : first.typeGuards) {
             for (SpecializationGroup other : others) {
                 if (!other.typeGuards.contains(typeGuard)) {
@@ -214,71 +182,23 @@
         // check for guards for required type casts
         for (Iterator<GuardExpression> iterator = guardMatches.iterator(); iterator.hasNext();) {
             GuardExpression guardMatch = iterator.next();
-
-            int signatureIndex = 0;
-            for (Parameter parameter : guardMatch.getResolvedGuard().getParameters()) {
-                signatureIndex++;
-                if (!parameter.getSpecification().isSignature()) {
-                    continue;
-                }
-
-                TypeMirror guardType = parameter.getType();
-
-                // object guards can be safely moved up
-                if (ElementUtils.isObject(guardType)) {
-                    continue;
-                }
-
-                // generic guards can be safely moved up
-                SpecializationData generic = first.node.getGenericSpecialization();
-                if (generic != null) {
-                    Parameter genericParameter = generic.findParameter(parameter.getLocalName());
-                    if (genericParameter != null && ElementUtils.typeEquals(genericParameter.getType(), guardType)) {
-                        continue;
-                    }
-                }
-
-                // signature index required for moving up guards
-                if (containsIndex(typeGuardsMatches, signatureIndex) || (first.getParent() != null && first.getParent().containsTypeGuardIndex(signatureIndex))) {
-                    continue;
-                }
-
+            if (!guardMatch.getExpression().findBoundVariables().isEmpty()) {
                 iterator.remove();
-                break;
             }
+            // TODO we need to be smarter here with bound parameters.
         }
 
-        if (assumptionMatches.isEmpty() && typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) {
+        if (typeGuardsMatches.isEmpty() && guardMatches.isEmpty()) {
             return null;
         }
 
         for (SpecializationGroup group : groups) {
-            group.assumptions.removeAll(assumptionMatches);
             group.typeGuards.removeAll(typeGuardsMatches);
             group.guards.removeAll(guardMatches);
         }
 
         List<SpecializationGroup> newChildren = new ArrayList<>(groups);
-        return new SpecializationGroup(newChildren, assumptionMatches, typeGuardsMatches, guardMatches);
-    }
-
-    private boolean containsTypeGuardIndex(int index) {
-        if (containsIndex(typeGuards, index)) {
-            return true;
-        }
-        if (parent != null) {
-            return parent.containsTypeGuardIndex(index);
-        }
-        return false;
-    }
-
-    private static boolean containsIndex(List<TypeGuard> typeGuards, int signatureIndex) {
-        for (TypeGuard guard : typeGuards) {
-            if (guard.signatureIndex == signatureIndex) {
-                return true;
-            }
-        }
-        return false;
+        return new SpecializationGroup(newChildren, typeGuardsMatches, guardMatches);
     }
 
     public static SpecializationGroup create(SpecializationData specialization) {
@@ -290,12 +210,12 @@
         for (SpecializationData specialization : specializations) {
             groups.add(new SpecializationGroup(specialization));
         }
-        return new SpecializationGroup(createCombinationalGroups(groups), Collections.<String> emptyList(), Collections.<TypeGuard> emptyList(), Collections.<GuardExpression> emptyList());
+        return new SpecializationGroup(createCombinationalGroups(groups), Collections.<TypeGuard> emptyList(), Collections.<GuardExpression> emptyList());
     }
 
     @Override
     public String toString() {
-        return "SpecializationGroup [assumptions=" + assumptions + ", typeGuards=" + typeGuards + ", guards=" + guards + "]";
+        return "SpecializationGroup [typeGuards=" + typeGuards + ", guards=" + guards + "]";
     }
 
     private static List<SpecializationGroup> createCombinationalGroups(List<SpecializationGroup> groups) {
@@ -423,26 +343,16 @@
         }
     }
 
-    public boolean isTypeGuardUsedInAnyGuardBelow(ProcessorContext context, SpecializationData source, TypeGuard typeGuard) {
-        NodeExecutionData execution = source.getNode().getChildExecutions().get(typeGuard.getSignatureIndex());
-
-        for (GuardExpression guard : guards) {
-            List<Parameter> guardParameters = guard.getResolvedGuard().findByExecutionData(execution);
-            Parameter sourceParameter = source.getSignatureParameter(typeGuard.getSignatureIndex());
-            for (Parameter guardParameter : guardParameters) {
-                if (sourceParameter.getTypeSystemType().needsCastTo(guardParameter.getType())) {
-                    return true;
-                }
-            }
+    public SpecializationGroup getPrevious() {
+        if (getParent() == null) {
+            return null;
         }
 
-        for (SpecializationGroup group : getChildren()) {
-            if (group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard)) {
-                return true;
-            }
+        List<SpecializationGroup> parentChildren = getParent().getChildren();
+        int index = parentChildren.indexOf(this);
+        if (index <= 0) {
+            return null;
         }
-
-        return false;
+        return parentChildren.get(index - 1);
     }
-
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -42,7 +42,9 @@
 
     @Override
     public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
-        return createDefaultMethodSpec(method, mirror, true, null);
+        MethodSpec spec = createDefaultMethodSpec(method, mirror, true, null);
+        spec.getAnnotations().add(new AnnotatedParameterSpec(getContext().getDeclaredType(Cached.class)));
+        return spec;
     }
 
     @Override
@@ -92,13 +94,6 @@
             specialization.setInsertBeforeName(insertBeforeName);
         }
 
-        List<String> guardDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
-        List<GuardExpression> guardExpressions = new ArrayList<>();
-        for (String guardDef : guardDefs) {
-            guardExpressions.add(new GuardExpression(guardDef, true));
-        }
-        specialization.setGuards(guardExpressions);
-
         List<String> containsDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "contains");
         Set<String> containsNames = specialization.getContainsNames();
         containsNames.clear();
@@ -114,15 +109,6 @@
 
         }
 
-        List<String> assumptionDefs = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions");
-        specialization.setAssumptions(assumptionDefs);
-
-        for (String assumption : assumptionDefs) {
-            if (!getNode().getAssumptions().contains(assumption)) {
-                specialization.addError("Undeclared assumption '%s' used. Use @NodeAssumptions to declare them.", assumption);
-            }
-        }
-
         return specialization;
     }
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java	Thu Feb 12 04:01:46 2015 +0100
@@ -132,7 +132,7 @@
         return null;
     }
 
-    public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List<TypeMirror> parameterTypes) {
+    public final E create(String id, int naturalOrder, ExecutableElement methodMetadata, AnnotationMirror mirror, TypeMirror returnType, List<VariableElement> parameterTypes) {
         TemplateMethod method = parser.parseImpl(createSpecification(methodMetadata, mirror), naturalOrder, id, methodMetadata, mirror, returnType, parameterTypes);
         if (method != null) {
             return create(method, method.hasErrors());
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -94,7 +94,7 @@
      * To implement these semantics, we tell the Truffle DSL to use a custom guard. The guard
      * function is defined in {@link #isString this class}, but could also be in any superclass.
      */
-    @Specialization(guards = "isString")
+    @Specialization(guards = "isString(left, right)")
     @TruffleBoundary
     protected String add(Object left, Object right) {
         return left.toString() + right.toString();
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java	Thu Feb 12 03:42:51 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java	Thu Feb 12 04:01:46 2015 +0100
@@ -49,15 +49,15 @@
     /**
      * Specialized method to write a primitive {@code long} value. This is only possible if the
      * local variable also has currently the type {@code long}, therefore a Truffle DSL
-     * {@link #isLongKind() custom guard} is specified.
+     * {@link #isLongKind(VirtualFrame) custom guard} is specified.
      */
-    @Specialization(guards = "isLongKind")
+    @Specialization(guards = "isLongKind(frame)")
     protected long writeLong(VirtualFrame frame, long value) {
         frame.setLong(getSlot(), value);
         return value;
     }
 
-    @Specialization(guards = "isBooleanKind")
+    @Specialization(guards = "isBooleanKind(frame)")
     protected boolean writeBoolean(VirtualFrame frame, boolean value) {
         frame.setBoolean(getSlot(), value);
         return value;
@@ -91,11 +91,13 @@
     /**
      * Guard function that the local variable has the type {@code long}.
      */
-    protected boolean isLongKind() {
+    @SuppressWarnings("unused")
+    protected boolean isLongKind(VirtualFrame frame) {
         return isKind(FrameSlotKind.Long);
     }
 
-    protected boolean isBooleanKind() {
+    @SuppressWarnings("unused")
+    protected boolean isBooleanKind(VirtualFrame frame) {
         return isKind(FrameSlotKind.Boolean);
     }
 
--- a/src/share/vm/classfile/systemDictionary.hpp	Thu Feb 12 03:42:51 2015 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Feb 12 04:01:46 2015 +0100
@@ -207,7 +207,6 @@
   GRAAL_ONLY(do_klass(Assumptions_ConcreteMethod_klass,      com_oracle_graal_api_code_Assumptions_ConcreteMethod,         Graal)) \
   GRAAL_ONLY(do_klass(Assumptions_NoFinalizableSubclass_klass, com_oracle_graal_api_code_Assumptions_NoFinalizableSubclass, Graal))\
   GRAAL_ONLY(do_klass(Assumptions_ConcreteSubtype_klass,     com_oracle_graal_api_code_Assumptions_ConcreteSubtype,        Graal)) \
-  GRAAL_ONLY(do_klass(Assumptions_MethodContents_klass,      com_oracle_graal_api_code_Assumptions_MethodContents,         Graal)) \
   GRAAL_ONLY(do_klass(Assumptions_CallSiteTargetValue_klass, com_oracle_graal_api_code_Assumptions_CallSiteTargetValue,    Graal)) \
   GRAAL_ONLY(do_klass(BytecodePosition_klass,                com_oracle_graal_api_code_BytecodePosition,                   Graal)) \
   GRAAL_ONLY(do_klass(DebugInfo_klass,                       com_oracle_graal_api_code_DebugInfo,                          Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Thu Feb 12 03:42:51 2015 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Thu Feb 12 04:01:46 2015 +0100
@@ -321,7 +321,6 @@
   GRAAL_ONLY(template(com_oracle_graal_api_meta_Kind,                           "com/oracle/graal/api/meta/Kind"))                                \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_LIRKind,                        "com/oracle/graal/api/meta/LIRKind"))                             \
   GRAAL_ONLY(template(com_oracle_graal_api_meta_AbstractValue,                  "com/oracle/graal/api/meta/AbstractValue"))                       \
-  GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_MethodContents,     "com/oracle/graal/api/code/Assumptions$MethodContents"))          \
   GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_ConcreteSubtype,    "com/oracle/graal/api/code/Assumptions$ConcreteSubtype"))         \
   GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_NoFinalizableSubclass, "com/oracle/graal/api/code/Assumptions$NoFinalizableSubclass")) \
   GRAAL_ONLY(template(com_oracle_graal_api_code_Assumptions_ConcreteMethod,     "com/oracle/graal/api/code/Assumptions$ConcreteMethod"))          \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Feb 12 03:42:51 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Thu Feb 12 04:01:46 2015 +0100
@@ -384,7 +384,7 @@
   return new MonitorValue(owner_value, lock_data_loc, eliminated);
 }
 
-void CodeInstaller::initialize_assumptions(oop compiled_code) {
+void CodeInstaller::initialize_dependencies(oop compiled_code) {
   JavaThread* thread = JavaThread::current();
   CompilerThread* compilerThread = thread->is_Compiler_thread() ? thread->as_CompilerThread() : NULL;
   _oop_recorder = new OopRecorder(&_arena, true);
@@ -395,9 +395,7 @@
     for (int i = 0; i < length; ++i) {
       Handle assumption = assumptions->obj_at(i);
       if (!assumption.is_null()) {
-        if (assumption->klass() == Assumptions_MethodContents::klass()) {
-          assumption_MethodContents(assumption);
-        } else if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) {
+        if (assumption->klass() == Assumptions_NoFinalizableSubclass::klass()) {
           assumption_NoFinalizableSubclass(assumption);
         } else if (assumption->klass() == Assumptions_ConcreteSubtype::klass()) {
           assumption_ConcreteSubtype(assumption);
@@ -412,6 +410,15 @@
       }
     }
   }
+  objArrayHandle methods = CompilationResult::methods(HotSpotCompiledCode::comp(compiled_code));
+  if (!methods.is_null()) {
+    int length = methods->length();
+    for (int i = 0; i < length; ++i) {
+      Handle method_handle = methods->obj_at(i);
+      methodHandle method = getMethodFromHotSpotMethod(method_handle());
+      _dependencies->assert_evol_method(method());
+    }
+  }
 }
 
 // constructor used to create a method
@@ -423,7 +430,7 @@
 
   CodeBuffer buffer(buffer_blob);
   jobject compiled_code_obj = JNIHandles::make_local(compiled_code());
-  initialize_assumptions(JNIHandles::resolve(compiled_code_obj));
+  initialize_dependencies(JNIHandles::resolve(compiled_code_obj));
 
   // Get instructions and constants CodeSections early because we need it.
   _instructions = buffer.insts();
@@ -638,12 +645,6 @@
   return true;
 }
 
-void CodeInstaller::assumption_MethodContents(Handle assumption) {
-  Handle method_handle = Assumptions_MethodContents::method(assumption());
-  methodHandle method = getMethodFromHotSpotMethod(method_handle());
-  _dependencies->assert_evol_method(method());
-}
-
 void CodeInstaller::assumption_NoFinalizableSubclass(Handle assumption) {
   Handle receiverType_handle = Assumptions_NoFinalizableSubclass::receiverType(assumption());
   Klass* receiverType = java_lang_Class::as_Klass(HotSpotResolvedObjectTypeImpl::javaClass(receiverType_handle));
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Thu Feb 12 03:42:51 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Thu Feb 12 04:01:46 2015 +0100
@@ -122,14 +122,13 @@
 private:
   // extract the fields of the CompilationResult
   void initialize_fields(oop target_method);
-  void initialize_assumptions(oop target_method);
+  void initialize_dependencies(oop target_method);
   
   int estimate_stub_entries();
   
   // perform data and call relocation on the CodeBuffer
   bool initialize_buffer(CodeBuffer& buffer);
 
-  void assumption_MethodContents(Handle assumption);
   void assumption_NoFinalizableSubclass(Handle assumption);
   void assumption_ConcreteSubtype(Handle assumption);
   void assumption_ConcreteMethod(Handle assumption);
--- a/src/share/vm/graal/graalJavaAccess.hpp	Thu Feb 12 03:42:51 2015 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Thu Feb 12 04:01:46 2015 +0100
@@ -96,12 +96,10 @@
     int_field(CompilationResult, totalFrameSize)                                                                                                               \
     int_field(CompilationResult, customStackAreaOffset)                                                                                                        \
     typeArrayOop_field(CompilationResult, targetCode, "[B")                                                                                                    \
-    objArrayOop_field(CompilationResult, assumptions, "[Lcom/oracle/graal/api/code/Assumptions$Assumption;")                                                                \
+    objArrayOop_field(CompilationResult, assumptions, "[Lcom/oracle/graal/api/code/Assumptions$Assumption;")                                                   \
+    objArrayOop_field(CompilationResult, methods, "[Lcom/oracle/graal/api/meta/ResolvedJavaMethod;")                                                           \
     int_field(CompilationResult, targetCodeSize)                                                                                                               \
   end_class                                                                                                                                                    \
-  start_class(Assumptions_MethodContents)                                                                                                                      \
-    oop_field(Assumptions_MethodContents, method, "Lcom/oracle/graal/api/meta/ResolvedJavaMethod;")                                                            \
-  end_class                                                                                                                                                    \
   start_class(Assumptions_NoFinalizableSubclass)                                                                                                               \
     oop_field(Assumptions_NoFinalizableSubclass, receiverType, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                 \
   end_class                                                                                                                                                    \