changeset 19329:57c53b1044a7

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Thu, 12 Feb 2015 20:47:20 +0100
parents fcefaa7f103d (current diff) 2778032e1beb (diff)
children 3370072ffbfb
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPluginsProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTierPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTierPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTierPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhaseSuite.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelSuites.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/ImportGuards.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventReceiver.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventReceiver.java graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventReceiver.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeBaseFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/PolymorphicNodeFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/SpecializedNodeFactory.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/GuardParser.java
diffstat 315 files changed, 9906 insertions(+), 7507 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Thu Feb 12 20:46:56 2015 +0100
+++ b/CHANGELOG.md	Thu Feb 12 20:47:20 2015 +0100
@@ -7,6 +7,7 @@
 ### Graal
 * Add utilities ModifiersProvider#isConcrete, ResolvedJavaMethod#hasBytecodes, ResolvedJavaMethod#hasReceiver to Graal API.
 * Add `GraalDirectives` API, containing methods to influence compiler behavior for unittests and microbenchmarks.
+* Introduce `LIRSuites`, an extensible configuration for the low-level compiler pipeline.
 * ...
 
 ### Truffle
@@ -18,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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.api.code;
 
-import static com.oracle.graal.api.meta.MetaUtil.*;
-
 import java.io.*;
 import java.lang.invoke.*;
 import java.util.*;
@@ -31,20 +29,25 @@
 import com.oracle.graal.api.meta.*;
 
 /**
- * Class for recording optimistic assumptions made during compilation.
+ * 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 {
 
         private static final long serialVersionUID = -1936652569665112915L;
     }
 
+    /**
+     * An assumption that a given class has no subclasses implementing {@link Object#finalize()}).
+     */
     public static final class NoFinalizableSubclass extends Assumption {
 
         private static final long serialVersionUID = 6451169735564055081L;
@@ -77,7 +80,7 @@
     }
 
     /**
-     * An assumption about a unique subtype of a given type.
+     * An assumption that a given type has a given unique subtype.
      */
     public static final class ConcreteSubtype extends Assumption {
 
@@ -125,7 +128,7 @@
     }
 
     /**
-     * An assumption about a unique implementation of a virtual method.
+     * An assumption that a given virtual method has a given unique implementation.
      */
     public static final class ConcreteMethod extends Assumption {
 
@@ -174,45 +177,12 @@
 
         @Override
         public String toString() {
-            return "ConcreteMethod[method=" + method.format("%H.%n(%p)") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)") + "]";
+            return "ConcreteMethod[method=" + method.format("%H.%n(%p)%r") + ", context=" + context.toJavaName() + ", impl=" + impl.format("%H.%n(%p)%r") + "]";
         }
     }
 
     /**
-     * An assumption that specified that a method was used during the compilation.
-     */
-    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)") + "]";
-        }
-    }
-
-    /**
-     * Assumption that a call site's method handle did not change.
+     * An assumption that a given call site's method handle did not change.
      */
     public static final class CallSiteTargetValue extends Assumption {
 
@@ -250,18 +220,7 @@
         }
     }
 
-    /**
-     * Array with the assumptions. This field is directly accessed from C++ code in the
-     * Graal/HotSpot implementation.
-     */
-    private Assumption[] list;
-    private boolean useOptimisticAssumptions;
-    private int count;
-
-    public Assumptions(boolean useOptimisticAssumptions) {
-        this.useOptimisticAssumptions = useOptimisticAssumptions;
-        list = new Assumption[4];
-    }
+    private final Set<Assumption> assumptions = new HashSet<>();
 
     /**
      * Returns whether any assumptions have been registered.
@@ -269,11 +228,7 @@
      * @return {@code true} if at least one assumption has been registered, {@code false} otherwise.
      */
     public boolean isEmpty() {
-        return count == 0;
-    }
-
-    public boolean useOptimisticAssumptions() {
-        return useOptimisticAssumptions;
+        return assumptions.isEmpty();
     }
 
     @Override
@@ -282,25 +237,15 @@
     }
 
     @Override
-    public String toString() {
-        return identityHashCodeString(this);
-    }
-
-    @Override
     public boolean equals(Object obj) {
         if (this == obj) {
             return true;
         }
         if (obj instanceof Assumptions) {
             Assumptions that = (Assumptions) obj;
-            if (useOptimisticAssumptions != that.useOptimisticAssumptions || count != that.count) {
+            if (!this.assumptions.equals(that.assumptions)) {
                 return false;
             }
-            for (int i = 0; i < count; i++) {
-                if (!list[i].equals(that.list[i])) {
-                    return false;
-                }
-            }
             return true;
         }
         return false;
@@ -308,28 +253,7 @@
 
     @Override
     public Iterator<Assumption> iterator() {
-        return new Iterator<Assumptions.Assumption>() {
-
-            int index;
-
-            @Override
-            public void remove() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public Assumption next() {
-                if (index >= count) {
-                    throw new NoSuchElementException();
-                }
-                return list[index++];
-            }
-
-            @Override
-            public boolean hasNext() {
-                return index < count;
-            }
-        };
+        return assumptions.iterator();
     }
 
     /**
@@ -338,7 +262,6 @@
      * @param receiverType the type that is assumed to have no finalizable subclasses
      */
     public void recordNoFinalizableSubclassAssumption(ResolvedJavaType receiverType) {
-        assert useOptimisticAssumptions;
         record(new NoFinalizableSubclass(receiverType));
     }
 
@@ -350,7 +273,6 @@
      * @param subtype the one concrete subtype
      */
     public void recordConcreteSubtype(ResolvedJavaType context, ResolvedJavaType subtype) {
-        assert useOptimisticAssumptions;
         record(new ConcreteSubtype(context, subtype));
     }
 
@@ -363,64 +285,30 @@
      * @param impl the concrete method that is the only possible target for the virtual call
      */
     public void recordConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType context, ResolvedJavaMethod impl) {
-        assert useOptimisticAssumptions;
         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) {
-        if (list == null) {
-            list = new Assumption[4];
-        } else {
-            for (int i = 0; i < count; ++i) {
-                if (assumption.equals(list[i])) {
-                    return;
-                }
-            }
-        }
-        if (list.length == count) {
-            Assumption[] newList = new Assumption[list.length * 2];
-            for (int i = 0; i < list.length; ++i) {
-                newList[i] = list[i];
-            }
-            list = newList;
-        }
-        list[count] = assumption;
-        count++;
+        assumptions.add(assumption);
     }
 
-    public Assumption[] getAssumptions() {
-        return list;
+    /**
+     * Gets a copy of the assumptions recorded in this object as an array.
+     */
+    public Assumption[] toArray() {
+        return assumptions.toArray(new Assumption[assumptions.size()]);
     }
 
-    public void record(Assumptions assumptions) {
-        for (int i = 0; i < assumptions.count; i++) {
-            record(assumptions.list[i]);
-        }
+    /**
+     * Copies assumptions recorded by another {@link Assumptions} object into this object.
+     */
+    public void record(Assumptions other) {
+        assert other != this;
+        assumptions.addAll(other.assumptions);
     }
 
-    public void print(PrintStream out) {
-        List<Assumption> nonNullList = new ArrayList<>();
-        if (list != null) {
-            for (int i = 0; i < list.length; ++i) {
-                Assumption a = list[i];
-                if (a != null) {
-                    nonNullList.add(a);
-                }
-            }
-        }
-
-        out.printf("%d assumptions:%n", nonNullList.size());
-        for (Assumption a : nonNullList) {
-            out.println(a.toString());
-        }
+    @Override
+    public String toString() {
+        return "Assumptions[" + assumptions + "]";
     }
 }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,6 +28,7 @@
 import java.io.*;
 import java.util.*;
 
+import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.code.CodeUtil.RefMapFormatter;
 import com.oracle.graal.api.meta.*;
 
@@ -528,7 +529,12 @@
 
     private ArrayList<CodeAnnotation> annotations;
 
-    private Assumptions assumptions;
+    private Assumption[] assumptions;
+
+    /**
+     * The list of the methods whose bytecodes were used as input to the compilation.
+     */
+    private ResolvedJavaMethod[] methods;
 
     public CompilationResult() {
         this(null);
@@ -564,12 +570,12 @@
                 this.targetCodeSize == that.targetCodeSize &&
                 Objects.equals(this.name, that.name) &&
                 Objects.equals(this.annotations, that.annotations) &&
-                Objects.equals(this.assumptions, that.assumptions) &&
                 Objects.equals(this.dataSection, that.dataSection) &&
                 Objects.equals(this.exceptionHandlers, that.exceptionHandlers) &&
                 Objects.equals(this.dataPatches, that.dataPatches) &&
                 Objects.equals(this.infopoints, that.infopoints) &&
                 Objects.equals(this.marks,  that.marks) &&
+                Arrays.equals(this.assumptions, that.assumptions) &&
                 Arrays.equals(targetCode, that.targetCode)) {
                 return true;
             }
@@ -606,12 +612,34 @@
         this.entryBCI = entryBCI;
     }
 
-    public void setAssumptions(Assumptions assumptions) {
+    /**
+     * Sets the assumptions made during compilation.
+     */
+    public void setAssumptions(Assumption[] assumptions) {
         this.assumptions = assumptions;
     }
 
-    public Assumptions getAssumptions() {
-        return assumptions;
+    /**
+     * 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() {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Thu Feb 12 20:47:20 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/BaselineBytecodeParser.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Thu Feb 12 20:47:20 2015 +0100
@@ -145,9 +145,9 @@
                     throw Debug.handle(e);
                 }
 
-                try (Scope s = Debug.scope("LowLevelTier", this)) {
-                    LowLevelSuites lowLevelSuites = backend.getSuites().getDefaultLowLevelSuites();
-                    return GraalCompiler.emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, gen, lowLevelSuites);
+                try (Scope s = Debug.scope("LIRTier", this)) {
+                    LIRSuites lirSuites = backend.getSuites().getDefaultLIRSuites();
+                    return GraalCompiler.emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, gen, lirSuites);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Thu Feb 12 20:47:20 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.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Feb 12 20:47:20 2015 +0100
@@ -122,23 +122,11 @@
     public static final OptionValue<Boolean> LoopUnswitch = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Expert)
-    public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
-
-    @Option(help = "", type = OptionType.Expert)
-    public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
-
-    @Option(help = "", type = OptionType.Expert)
     public static final OptionValue<Float> MinimumPeelProbability = new OptionValue<>(0.35f);
 
     @Option(help = "", type = OptionType.Expert)
     public static final OptionValue<Integer> LoopMaxUnswitch = new OptionValue<>(3);
 
-    @Option(help = "", type = OptionType.Expert)
-    public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(50);
-
-    @Option(help = "", type = OptionType.Expert)
-    public static final OptionValue<Integer> LoopUnswitchUncertaintyBoost = new OptionValue<>(5);
-
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> UseLoopLimitChecks = new OptionValue<>(true);
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -305,9 +305,8 @@
     }
 
     private void processMethod(final String snippet) {
-        graph = parseEager(snippet);
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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,10 +316,8 @@
     }
 
     private void compareGraphs(final String snippet, final String referenceSnippet, final boolean loopPeeling, final boolean excludeVirtual) {
-        graph = parseEager(snippet);
-
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        graph = parseEager(snippet, AllowAssumptions.NO);
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         canonicalizer.apply(graph, context);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
@@ -334,7 +331,7 @@
         new DeadCodeEliminationPhase().apply(graph);
         canonicalizer.apply(graph, context);
 
-        StructuredGraph referenceGraph = parseEager(referenceSnippet);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Thu Feb 12 20:47:20 2015 +0100
@@ -44,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.*;
@@ -69,7 +70,7 @@
 
         PhaseSuite<HighTierContext> graphBuilderSuite = new PhaseSuite<>();
         graphBuilderSuite.appendPhase(new GraphBuilderPhase(GraphBuilderConfiguration.getEagerDefault()));
-        HighTierContext context = new HighTierContext(providers, new Assumptions(false), null, graphBuilderSuite, OptimisticOptimizations.NONE);
+        HighTierContext context = new HighTierContext(providers, null, graphBuilderSuite, OptimisticOptimizations.NONE);
 
         Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
 
@@ -138,7 +139,7 @@
                         if (matches(filters, methodName)) {
                             executor.execute(() -> {
                                 ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
-                                StructuredGraph graph = new StructuredGraph(method);
+                                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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,8 +26,8 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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,8 +35,8 @@
 public class CompareCanonicalizerTest extends GraalCompilerTest {
 
     private StructuredGraph getCanonicalizedGraph(String name) {
-        StructuredGraph graph = parseEager(name);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         return graph;
     }
 
@@ -48,13 +48,12 @@
 
     @Test
     public void testCanonicalComparison() {
-        StructuredGraph referenceGraph = parseEager("referenceCanonicalComparison");
+        StructuredGraph referenceGraph = parseEager("referenceCanonicalComparison", AllowAssumptions.NO);
         for (int i = 1; i < 4; i++) {
-            StructuredGraph graph = parseEager("canonicalCompare" + i);
+            StructuredGraph graph = parseEager("canonicalCompare" + i, AllowAssumptions.NO);
             assertEquals(referenceGraph, graph);
         }
-        Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders(), assumptions));
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders()));
         for (int i = 1; i < 4; i++) {
             StructuredGraph graph = getCanonicalizedGraph("canonicalCompare" + i);
             assertEquals(referenceGraph, graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -25,6 +25,7 @@
 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.*;
@@ -90,9 +91,9 @@
 
     @Test
     public void testRedundantCompares() {
-        StructuredGraph graph = parseEager("testRedundantComparesSnippet");
+        StructuredGraph graph = parseEager("testRedundantComparesSnippet", AllowAssumptions.YES);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        PhaseContext context = new PhaseContext(getProviders(), null);
+        PhaseContext context = new PhaseContext(getProviders());
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
@@ -113,10 +114,10 @@
     @Test
     @Ignore
     public void testInstanceOfCheckCastLowered() {
-        StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet");
+        StructuredGraph graph = parseEager("testInstanceOfCheckCastSnippet", AllowAssumptions.YES);
 
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
-        PhaseContext context = new PhaseContext(getProviders(), null);
+        PhaseContext context = new PhaseContext(getProviders());
 
         new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,10 +24,10 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -81,12 +81,12 @@
 
     private void test(final String snippet) {
         try (Scope s = Debug.scope("DegeneratedLoopsTest", new DebugDumpScope(snippet))) {
-            StructuredGraph graph = parseEager(snippet);
-            HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+            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);
+            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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,10 +24,10 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -106,11 +106,11 @@
     }
 
     private StructuredGraph compileSnippet(final String snippet, final int checkcasts, final int afterCanon) {
-        final StructuredGraph graph = parseEager(snippet);
+        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());
-            new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+            new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
             Assert.assertEquals(afterCanon, graph.getNodes().filter(CheckCastNode.class).count());
             return graph;
         } catch (Throwable e) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -35,6 +35,7 @@
 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.*;
@@ -60,28 +61,30 @@
         }
     }
 
-    private StructuredGraph parseAndProcess(Class<?> cl, Assumptions assumptions) {
+    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);
+        StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
 
         GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault();
-        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), conf, OptimisticOptimizations.ALL).apply(graph);
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         return graph;
     }
 
-    private void checkForRegisterFinalizeNode(Class<?> cl, boolean shouldContainFinalizer, boolean optimistic) {
-        Assumptions assumptions = new Assumptions(optimistic);
-        StructuredGraph graph = parseAndProcess(cl, assumptions);
+    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 : assumptions) {
-            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, false);
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, true);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), true, AllowAssumptions.NO);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerEverAAAA"), false, AllowAssumptions.YES);
 
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, true);
+            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), false, AllowAssumptions.YES);
 
-            checkForRegisterFinalizeNode(loader.findClass("WithFinalizerAAAA"), true, true);
-            checkForRegisterFinalizeNode(loader.findClass("NoFinalizerYetAAAA"), true, true);
+            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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,11 +24,11 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -58,8 +58,8 @@
     private void test(final String snippet) {
         try (Scope s = Debug.scope("FloatingReadTest", new DebugDumpScope(snippet))) {
 
-            StructuredGraph graph = parseEager(snippet);
-            PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+            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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -53,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.*;
@@ -71,7 +72,7 @@
  * <p>
  * White box tests for Graal compiler transformations use this pattern:
  * <ol>
- * <li>Create a graph by {@linkplain #parseEager(String) 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>
@@ -90,7 +91,7 @@
     private final Providers providers;
     private final Backend backend;
     private final DerivedOptionValue<Suites> suites;
-    private final DerivedOptionValue<LowLevelSuites> lowLevelSuites;
+    private final DerivedOptionValue<LIRSuites> lirSuites;
 
     /**
      * Can be overridden by unit tests to verify properties of the graph.
@@ -166,8 +167,8 @@
         return ret;
     }
 
-    protected LowLevelSuites createLowLevelSuites() {
-        LowLevelSuites ret = backend.getSuites().createLowLevelSuites();
+    protected LIRSuites createLIRSuites() {
+        LIRSuites ret = backend.getSuites().createLIRSuites();
         return ret;
     }
 
@@ -175,7 +176,7 @@
         this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         this.providers = getBackend().getProviders();
         this.suites = new DerivedOptionValue<>(this::createSuites);
-        this.lowLevelSuites = new DerivedOptionValue<>(this::createLowLevelSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
         installSubstitutions();
     }
 
@@ -196,7 +197,7 @@
         }
         this.providers = backend.getProviders();
         this.suites = new DerivedOptionValue<>(this::createSuites);
-        this.lowLevelSuites = new DerivedOptionValue<>(this::createLowLevelSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
         installSubstitutions();
     }
 
@@ -364,8 +365,8 @@
         return suites.getValue();
     }
 
-    protected LowLevelSuites getLowLevelSuites() {
-        return lowLevelSuites.getValue();
+    protected LIRSuites getLIRSuites() {
+        return lirSuites.getValue();
     }
 
     protected Providers getProviders() {
@@ -661,7 +662,7 @@
 
     /**
      * Gets installed code for a given method, compiling it first if necessary. The graph is parsed
-     * {@link #parseEager(ResolvedJavaMethod) eagerly}.
+     * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions) eagerly}.
      */
     protected InstalledCode getCode(ResolvedJavaMethod method) {
         return getCode(method, null);
@@ -735,10 +736,10 @@
      * is null.
      *
      * The default implementation in {@link GraalCompilerTest} is to call
-     * {@link #parseEager(ResolvedJavaMethod)}.
+     * {@link #parseEager(ResolvedJavaMethod, AllowAssumptions)}.
      */
     protected StructuredGraph parseForCompile(ResolvedJavaMethod method) {
-        return parseEager(method);
+        return parseEager(method, AllowAssumptions.YES);
     }
 
     /**
@@ -754,7 +755,7 @@
         lastCompiledGraph = graphToCompile;
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graphToCompile.method(), false);
         Request<CompilationResult> request = new Request<>(graphToCompile, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                        OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), getLowLevelSuites(), new CompilationResult(),
+                        OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), getLIRSuites(), new CompilationResult(),
                         CompilationResultBuilderFactory.Default);
         return GraalCompiler.compile(request);
     }
@@ -815,16 +816,16 @@
      *
      * @param methodName the name of the method in {@code this.getClass()} to be parsed
      */
-    protected StructuredGraph parseProfiled(String methodName) {
-        return parseProfiled(getResolvedJavaMethod(methodName));
+    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) {
-        return parse1(m, getDefaultGraphBuilderSuite());
+    protected StructuredGraph parseProfiled(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parse1(m, getDefaultGraphBuilderSuite(), allowAssumptions);
     }
 
     /**
@@ -833,31 +834,31 @@
      *
      * @param methodName the name of the method in {@code this.getClass()} to be parsed
      */
-    protected StructuredGraph parseEager(String methodName) {
-        return parseEager(getResolvedJavaMethod(methodName));
+    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) {
-        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getEagerDefault()));
+    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) {
-        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()));
+    protected StructuredGraph parseDebug(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
+        return parse1(m, getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()), allowAssumptions);
     }
 
-    private StructuredGraph parse1(ResolvedJavaMethod javaMethod, PhaseSuite<HighTierContext> graphBuilderSuite) {
+    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);
-            graphBuilderSuite.apply(graph, new HighTierContext(providers, null, null, graphBuilderSuite, OptimisticOptimizations.ALL));
+            StructuredGraph graph = new StructuredGraph(javaMethod, allowAssumptions);
+            graphBuilderSuite.apply(graph, new HighTierContext(providers, null, graphBuilderSuite, OptimisticOptimizations.ALL));
             return graph;
         } catch (Throwable e) {
             throw Debug.handle(e);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,10 +26,10 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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,11 +180,11 @@
     }
 
     private void testCombinedIf(String snippet, int count) {
-        StructuredGraph graph = parseEager(snippet);
-        PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+        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);
-        MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+        MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
         new GuardLoweringPhase().apply(graph, midContext);
         new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
         new ValueAnchorCleanupPhase().apply(graph);
@@ -193,19 +193,19 @@
     }
 
     private void test(String snippet) {
-        StructuredGraph graph = parseEager(snippet);
+        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()) {
             n.replaceFirstInput(param, constant);
         }
         Debug.dump(graph, "Graph");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) {
             fs.replaceFirstInput(param, null);
             param.safeDelete();
         }
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.api.code.CodeUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static org.junit.Assert.*;
 
 import org.junit.*;
@@ -36,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.*;
 
@@ -58,10 +60,10 @@
     @Test
     public void callInfopoints() {
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
-        final StructuredGraph graph = parseEager(method);
+        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(), getLowLevelSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        OptimisticOptimizations.ALL, getProfilingInfo(graph), null, getSuites(), getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
             if (sp instanceof Call) {
@@ -73,7 +75,7 @@
     @Test
     public void lineInfopoints() {
         final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
-        final StructuredGraph graph = parseDebug(method);
+        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) {
@@ -84,7 +86,7 @@
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
         PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault());
         final CompilationResult cr = compileGraph(graph, cc, graph.method(), getProviders(), getBackend(), getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL,
-                        getProfilingInfo(graph), getSpeculationLog(), getSuites(), getLowLevelSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        getProfilingInfo(graph), getSpeculationLog(), getSuites(), getLIRSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
         int lineSPs = 0;
         for (Infopoint sp : cr.getInfopoints()) {
             assertNotNull(sp.reason);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -25,6 +25,7 @@
 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.*;
 
@@ -112,8 +113,8 @@
     }
 
     private StructuredGraph getCanonicalizedGraph(String snippet) {
-        StructuredGraph graph = parseEager(snippet);
-        new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders(), null));
+        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);
             state.safeDelete();
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,8 +26,8 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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,13 +61,12 @@
     }
 
     private void test(String snippet) {
-        StructuredGraph graph = parseProfiled(snippet);
+        StructuredGraph graph = parseProfiled(snippet, AllowAssumptions.NO);
         Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
             hints.put(invoke, 1000d);
         }
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,8 +26,8 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -71,18 +71,17 @@
     }
 
     private void test(String snippet) {
-        StructuredGraph graph = parseEager(snippet);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         Map<Invoke, Double> hints = new HashMap<>();
         for (Invoke invoke : graph.getInvokes()) {
             hints.put(invoke, 1000d);
         }
 
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -62,7 +62,7 @@
         test("testSynchronizedSnippet", new A(), new A());
 
         StructuredGraph graph = getGraph("testSynchronizedSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new LockEliminationPhase().apply(graph);
         assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -80,7 +80,7 @@
         test("testSynchronizedMethodSnippet", new A());
 
         StructuredGraph graph = getGraph("testSynchronizedMethodSnippet");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), null));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new LockEliminationPhase().apply(graph);
         assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
         assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
@@ -88,9 +88,8 @@
 
     private StructuredGraph getGraph(String snippet) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
-        StructuredGraph graph = parseEager(method);
-        Assumptions assumptions = new Assumptions(true);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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);
         new CanonicalizerPhase(true).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,12 +24,12 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 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.*;
 
@@ -121,8 +121,8 @@
     }
 
     private void test(String snippet, String referenceSnippet) {
-        final StructuredGraph graph = parseEager(snippet);
-        final StructuredGraph referenceGraph = parseEager(referenceSnippet);
+        final StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        final StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
 
         new LoopUnswitchingPhase().apply(graph);
 
@@ -134,9 +134,8 @@
             ((StateSplit) stateSplit).setStateAfter(null);
         }
 
-        Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
-        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders()));
         try (Scope s = Debug.scope("Test", new DebugDumpScope("Test:" + snippet))) {
             assertEquals(referenceGraph, graph);
         } catch (Throwable e) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -29,12 +29,12 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 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,11 +596,10 @@
     }
 
     private SchedulePhase getFinalSchedule(final String snippet, final TestMode mode, final SchedulingStrategy schedulingStrategy) {
-        final StructuredGraph graph = parseEager(snippet);
+        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)) {
-                Assumptions assumptions = new Assumptions(false);
-                HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+                HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
                 canonicalizer.apply(graph, context);
                 if (mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
@@ -623,7 +622,7 @@
                 new FloatingReadPhase().apply(graph);
                 new RemoveValueProxyPhase().apply(graph);
 
-                MidTierContext midContext = new MidTierContext(getProviders(), assumptions, getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+                MidTierContext midContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
                 new GuardLoweringPhase().apply(graph, midContext);
                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
                 new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
 
@@ -57,9 +57,9 @@
     }
 
     private void testReturnCount(String snippet, int returnCount) {
-        StructuredGraph graph = parseEager(snippet);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+        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");
         assertDeepEquals(returnCount, graph.getNodes(ReturnNode.class).count());
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,10 +28,10 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         ParameterNode param = graph.getNodes(ParameterNode.class).first();
         if (param != null) {
             ConstantNode constant = ConstantNode.forInt(0, graph);
@@ -96,8 +96,7 @@
         for (Invoke invoke : graph.getInvokes()) {
             hints.put(invoke, 1000d);
         }
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
         new InliningPhase(hints, new CanonicalizerPhase(true)).apply(graph, context);
         new CanonicalizerPhase(true).apply(graph, context);
         new DeadCodeEliminationPhase().apply(graph);
@@ -106,7 +105,7 @@
 
     private void test(String snippet) {
         StructuredGraph graph = parseAndProcess(snippet);
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,6 +28,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.cfg.*;
 import com.oracle.graal.nodes.java.*;
 
@@ -145,7 +146,7 @@
     }
 
     private void test(String snippet, int rootExits, int nestedExits, int innerExits) {
-        StructuredGraph graph = parseEager(snippet);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PhiCreationTests.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,6 +26,7 @@
 
 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.
@@ -40,7 +41,7 @@
 
     @Test
     public void test1() {
-        StructuredGraph graph = parseEager("test1Snippet");
+        StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
 
@@ -53,7 +54,7 @@
 
     @Test
     public void test2() {
-        StructuredGraph graph = parseEager("test2Snippet");
+        StructuredGraph graph = parseEager("test2Snippet", AllowAssumptions.YES);
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
 
@@ -66,7 +67,7 @@
 
     @Test
     public void test3() {
-        StructuredGraph graph = parseEager("test3Snippet");
+        StructuredGraph graph = parseEager("test3Snippet", AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext());
     }
@@ -82,7 +83,7 @@
 
     @Test
     public void test4() {
-        StructuredGraph graph = parseEager("test4Snippet");
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,12 +24,12 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 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.*;
@@ -91,8 +91,8 @@
     }
 
     private StructuredGraph compileTestSnippet(final String snippet) {
-        StructuredGraph graph = parseEager(snippet);
-        PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+        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);
         canonicalizer.apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushThroughIfTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushThroughIfTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -57,21 +57,21 @@
     }
 
     private void test(String snippet, String reference) {
-        StructuredGraph graph = parseEager(snippet);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
         for (FrameState fs : graph.getNodes(FrameState.class).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
-        StructuredGraph referenceGraph = parseEager(reference);
+        StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
         for (FrameState fs : referenceGraph.getNodes(FrameState.class).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
-        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders(), new Assumptions(false)));
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders()));
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,10 +24,10 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -81,8 +81,8 @@
         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);
-            PhaseContext context = new PhaseContext(getProviders(), new Assumptions(false));
+            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);
             new FloatingReadPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
 
@@ -243,11 +243,10 @@
     }
 
     private <T extends Node & IterableNodeType> void test(String test, String ref) {
-        StructuredGraph testGraph = parseEager(test);
-        Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase(true).apply(testGraph, new PhaseContext(getProviders(), assumptions));
-        StructuredGraph refGraph = parseEager(ref);
-        new CanonicalizerPhase(true).apply(refGraph, new PhaseContext(getProviders(), assumptions));
+        StructuredGraph testGraph = parseEager(test, AllowAssumptions.NO);
+        new CanonicalizerPhase(true).apply(testGraph, new PhaseContext(getProviders()));
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
 
@@ -130,12 +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);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         Debug.dump(graph, "Graph");
-        Assumptions assumptions = new Assumptions(false);
-        PhaseContext context = new PhaseContext(getProviders(), assumptions);
+        PhaseContext context = new PhaseContext(getProviders());
         new CanonicalizerPhase(true).apply(graph, context);
-        StructuredGraph referenceGraph = parseEager(referenceSnippet);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -30,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.*;
@@ -51,7 +52,7 @@
 
     @Test
     public void testValueProxyInputs() {
-        StructuredGraph graph = parseEager("testValueProxyInputsSnippet");
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -30,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 {
@@ -40,7 +41,7 @@
 
     @Test
     public void testImplies() {
-        StructuredGraph graph = new StructuredGraph();
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
 
@@ -109,8 +109,8 @@
     }
 
     private void testZeroReturn(String methodName) {
-        StructuredGraph graph = parseEager(methodName);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
 
@@ -87,10 +87,10 @@
 
     private void test(final String snippet) {
         // No debug scope to reduce console noise for @Test(expected = ...) tests
-        StructuredGraph graph = parseEager(snippet);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         Debug.dump(graph, "Graph");
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
-        StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,11 +26,11 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
 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.*;
@@ -170,20 +170,19 @@
     }
 
     private void test(String snippet, String referenceSnippet) {
-        StructuredGraph graph = parseEager(snippet);
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
         Debug.dump(graph, "Graph");
-        Assumptions assumptions = new Assumptions(false);
         /*
          * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase,
          * tail-duplication gets activated thus resulting in a graph with more nodes than the
          * reference graph.
          */
-        new ConditionalEliminationPhase().apply(graph, new PhaseContext(getProviders(), assumptions));
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new ConditionalEliminationPhase().apply(graph, new PhaseContext(getProviders()));
+        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(), assumptions));
-        StructuredGraph referenceGraph = parseEager(referenceSnippet);
-        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
+        StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO);
+        new CanonicalizerPhase(true).apply(referenceGraph, new PhaseContext(getProviders()));
         assertEquals(referenceGraph, graph);
     }
 
@@ -230,10 +229,9 @@
     }
 
     private <T extends Node> void testHelper(String snippet, Class<T> clazz) {
-        StructuredGraph graph = parseEager(snippet);
-        Assumptions assumptions = new Assumptions(false);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), 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);
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext());
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,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);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.compiler.test.backend;
 
 import static com.oracle.graal.api.code.CodeUtil.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.CallingConvention.Type;
@@ -47,18 +46,16 @@
     }
 
     protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) {
-        final Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
-
         SchedulePhase schedule = null;
         try (Scope s = Debug.scope("FrontEnd")) {
-            schedule = GraalCompiler.emitFrontEnd(getProviders(), getBackend().getTarget(), graph, assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE,
+            schedule = GraalCompiler.emitFrontEnd(getProviders(), getBackend().getTarget(), graph, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE,
                             graph.method().getProfilingInfo(), null, getSuites());
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
 
         CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
-        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc, null, getLowLevelSuites());
+        LIRGenerationResult lirGen = GraalCompiler.emitLIR(getBackend(), getBackend().getTarget(), schedule, graph, null, cc, null, getLIRSuites());
         return lirGen;
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,6 +28,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.phases.common.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -51,8 +52,8 @@
     @Test
     public void test1() {
         final ResolvedJavaMethod javaMethod = getResolvedJavaMethod("testMethod");
-        final StructuredGraph graph = parseEager(javaMethod);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+        final StructuredGraph graph = parseEager(javaMethod, AllowAssumptions.NO);
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new DeadCodeEliminationPhase().apply(graph);
 
         for (ConstantNode node : ConstantNode.getConstantNodes(graph)) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -30,6 +30,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;
 
 public final class MonitorDeoptTest extends GraalCompilerTest {
 
@@ -134,7 +135,7 @@
     public void run0() throws Throwable {
         ResolvedJavaMethod javaMethod = getResolvedJavaMethod("test");
 
-        StructuredGraph graph = parseEager(javaMethod);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,13 +26,13 @@
 
 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.debug.*;
 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.*;
@@ -149,12 +149,11 @@
 
     protected void prepareGraph(String snippet, final boolean iterativeEscapeAnalysis) {
         ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
-        graph = new StructuredGraph(method);
+        graph = new StructuredGraph(method, AllowAssumptions.NO);
         try (Scope s = Debug.scope(getClass(), graph, method, getCodeCache())) {
-            Assumptions assumptions = new Assumptions(false);
-            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), assumptions, getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
+            new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
                             OptimisticOptimizations.ALL).apply(graph);
-            context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+            context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
             new DeadCodeEliminationPhase().apply(graph);
             new CanonicalizerPhase(true).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,7 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
+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.*;
@@ -40,9 +40,8 @@
 
     @Override
     protected void processMethod(final String snippet) {
-        graph = parseEager(snippet);
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,10 +28,10 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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,8 +84,8 @@
     }
 
     private void processMethod(final String snippet) {
-        graph = parseEager(snippet);
-        HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,9 +28,9 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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,9 +244,8 @@
     }
 
     protected void processMethod(final String snippet) {
-        graph = parseEager(snippet);
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,12 +24,12 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.test.*;
 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.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -39,7 +39,7 @@
 
 /**
  * Tests {@link AbstractNewObjectNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)}.
- * 
+ *
  */
 public class PoorMansEATest extends GraalCompilerTest {
     public static class A {
@@ -59,11 +59,10 @@
 
     private void test(final String snippet) {
         try (Scope s = Debug.scope("PoorMansEATest", new DebugDumpScope(snippet))) {
-            StructuredGraph graph = parseEager(snippet);
-            Assumptions assumptions = new Assumptions(false);
-            HighTierContext highTierContext = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+            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(), assumptions);
+            PhaseContext context = new PhaseContext(getProviders());
             new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
 
             // remove framestates in order to trigger the simplification.
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,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.*;
@@ -231,10 +232,9 @@
     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) : parseEager(method);
+            StructuredGraph graph = eagerInfopointMode ? parseDebug(method, AllowAssumptions.YES) : parseEager(method, AllowAssumptions.YES);
             PhaseSuite<HighTierContext> graphBuilderSuite = eagerInfopointMode ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getFullDebugDefault()) : getDefaultGraphBuilderSuite();
-            Assumptions assumptions = new Assumptions(true);
-            HighTierContext context = new HighTierContext(getProviders(), assumptions, null, graphBuilderSuite, OptimisticOptimizations.ALL);
+            HighTierContext context = new HighTierContext(getProviders(), null, graphBuilderSuite, OptimisticOptimizations.ALL);
             Debug.dump(graph, "Graph");
             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/tutorial/InvokeGraal.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Thu Feb 12 20:47:20 2015 +0100
@@ -37,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.*;
@@ -78,9 +79,11 @@
 
             /*
              * The graph that is compiled. We leave it empty (no nodes added yet). This means that
-             * it will be filled according to the graphBuilderSuite defined below.
+             * it will be filled according to the graphBuilderSuite defined below. We also specify
+             * that we want the compilation to make optimistic assumptions about runtime state such
+             * as the loaded class hierarchy.
              */
-            StructuredGraph graph = new StructuredGraph(method);
+            StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.YES);
 
             /*
              * The phases used to build the graph. Usually this is just the GraphBuilderPhase. If
@@ -97,7 +100,7 @@
             /*
              * The low-level phases that are applied to the low-level representation.
              */
-            LowLevelSuites lowLevelSuites = backend.getSuites().createLowLevelSuites();
+            LIRSuites lirSuites = backend.getSuites().createLIRSuites();
 
             /*
              * The calling convention for the machine code. You should have a very good reason
@@ -123,7 +126,7 @@
             SpeculationLog speculationLog = null;
 
             /* Invoke the whole Graal compilation pipeline. */
-            GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, lowLevelSuites,
+            GraalCompiler.compileGraph(graph, callingConvention, method, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, lirSuites,
                             compilationResult, factory);
 
             /*
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
@@ -33,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.*;
@@ -210,7 +210,7 @@
                  * Build the Graal graph for the method using the bytecode parser provided by Graal.
                  */
 
-                StructuredGraph graph = new StructuredGraph(method);
+                StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
                 /*
                  * Support for graph dumping, IGV uses this information to show the method name of a
                  * graph.
@@ -236,9 +236,8 @@
                      * wrong.
                      */
                     OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
-                    Assumptions assumptions = new Assumptions(false);
 
-                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, null, graphBuilderConfig, optimisticOpts);
+                    GraphBuilderPhase.Instance graphBuilder = new GraphBuilderPhase.Instance(metaAccess, stampProvider, null, graphBuilderConfig, optimisticOpts);
                     graphBuilder.apply(graph);
                 } catch (Throwable ex) {
                     Debug.handle(ex);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import static com.oracle.graal.compiler.GraalCompiler.Options.*;
 import static com.oracle.graal.compiler.MethodFilter.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
 
 import java.util.*;
@@ -45,9 +44,9 @@
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.lir.phases.LowLevelHighTierPhase.LowLevelHighTierContext;
-import com.oracle.graal.lir.phases.LowLevelLowTierPhase.LowLevelLowTierContext;
-import com.oracle.graal.lir.phases.LowLevelMidTierPhase.LowLevelMidTierContext;
+import com.oracle.graal.lir.phases.LIRHighTierPhase.LIRHighTierContext;
+import com.oracle.graal.lir.phases.LIRLowTierPhase.LIRLowTierContext;
+import com.oracle.graal.lir.phases.LIRMidTierPhase.LIRMidTierContext;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
@@ -144,7 +143,7 @@
         public final ProfilingInfo profilingInfo;
         public final SpeculationLog speculationLog;
         public final Suites suites;
-        public final LowLevelSuites lowLevelSuites;
+        public final LIRSuites lirSuites;
         public final T compilationResult;
         public final CompilationResultBuilderFactory factory;
 
@@ -162,13 +161,13 @@
          * @param profilingInfo
          * @param speculationLog
          * @param suites
-         * @param lowLevelSuites
+         * @param lirSuites
          * @param compilationResult
          * @param factory
          */
         public Request(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, TargetDescription target,
                         Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo,
-                        SpeculationLog speculationLog, Suites suites, LowLevelSuites lowLevelSuites, T compilationResult, CompilationResultBuilderFactory factory) {
+                        SpeculationLog speculationLog, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
             this.graph = graph;
             this.cc = cc;
             this.installedCodeOwner = installedCodeOwner;
@@ -181,7 +180,7 @@
             this.profilingInfo = profilingInfo;
             this.speculationLog = speculationLog;
             this.suites = suites;
-            this.lowLevelSuites = lowLevelSuites;
+            this.lirSuites = lirSuites;
             this.compilationResult = compilationResult;
             this.factory = factory;
         }
@@ -207,8 +206,8 @@
      */
     public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
                     TargetDescription target, Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts,
-                    ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, LowLevelSuites lowLevelSuites, T compilationResult, CompilationResultBuilderFactory factory) {
-        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, lowLevelSuites,
+                    ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
+        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, lirSuites,
                         compilationResult, factory));
     }
 
@@ -220,9 +219,8 @@
     public static <T extends CompilationResult> T compile(Request<T> r) {
         assert !r.graph.isFrozen();
         try (Scope s0 = Debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache())) {
-            Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
-            SchedulePhase schedule = emitFrontEnd(r.providers, r.target, r.graph, assumptions, r.cache, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.speculationLog, r.suites);
-            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, assumptions, schedule, null, r.lowLevelSuites);
+            SchedulePhase schedule = emitFrontEnd(r.providers, r.target, r.graph, r.cache, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.speculationLog, r.suites);
+            emitBackEnd(r.graph, null, r.cc, r.installedCodeOwner, r.backend, r.target, r.compilationResult, r.factory, schedule, null, r.lirSuites);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -240,14 +238,14 @@
     /**
      * Builds the graph, optimizes it.
      */
-    public static SchedulePhase emitFrontEnd(Providers providers, TargetDescription target, StructuredGraph graph, Assumptions assumptions, Map<ResolvedJavaMethod, StructuredGraph> cache,
+    public static SchedulePhase emitFrontEnd(Providers providers, TargetDescription target, StructuredGraph graph, Map<ResolvedJavaMethod, StructuredGraph> cache,
                     PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, SpeculationLog speculationLog, Suites suites) {
         try (Scope s = Debug.scope("FrontEnd"); TimerCloseable a = FrontEnd.start()) {
             if (speculationLog != null) {
                 speculationLog.collectFailedSpeculations();
             }
 
-            HighTierContext highTierContext = new HighTierContext(providers, assumptions, cache, graphBuilderSuite, optimisticOpts);
+            HighTierContext highTierContext = new HighTierContext(providers, cache, graphBuilderSuite, optimisticOpts);
             if (graph.start().next() == null) {
                 graphBuilderSuite.apply(graph, highTierContext);
                 new DeadCodeEliminationPhase(Optional).apply(graph);
@@ -258,11 +256,11 @@
             suites.getHighTier().apply(graph, highTierContext);
             graph.maybeCompress();
 
-            MidTierContext midTierContext = new MidTierContext(providers, assumptions, target, optimisticOpts, profilingInfo, speculationLog);
+            MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo, speculationLog);
             suites.getMidTier().apply(graph, midTierContext);
             graph.maybeCompress();
 
-            LowTierContext lowTierContext = new LowTierContext(providers, assumptions, target);
+            LowTierContext lowTierContext = new LowTierContext(providers, target);
             suites.getLowTier().apply(graph, lowTierContext);
             graph.maybeCompress();
 
@@ -277,13 +275,12 @@
     }
 
     public static <T extends CompilationResult> void emitBackEnd(StructuredGraph graph, Object stub, CallingConvention cc, ResolvedJavaMethod installedCodeOwner, Backend backend,
-                    TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, Assumptions assumptions, SchedulePhase schedule, RegisterConfig registerConfig,
-                    LowLevelSuites lowLevelSuites) {
+                    TargetDescription target, T compilationResult, CompilationResultBuilderFactory factory, SchedulePhase schedule, RegisterConfig registerConfig, LIRSuites lirSuites) {
         try (TimerCloseable a = BackEnd.start()) {
             LIRGenerationResult lirGen = null;
-            lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig, lowLevelSuites);
+            lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig, lirSuites);
             try (Scope s = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
-                emitCode(backend, assumptions, lirGen, compilationResult, installedCodeOwner, factory);
+                emitCode(backend, graph.getAssumptions(), graph.getMethods(), lirGen, compilationResult, installedCodeOwner, factory);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
@@ -304,7 +301,7 @@
     }
 
     public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc,
-                    RegisterConfig registerConfig, LowLevelSuites lowLevelSuites) {
+                    RegisterConfig registerConfig, LIRSuites lirSuites) {
         List<Block> blocks = schedule.getCFG().getBlocks();
         Block startBlock = schedule.getCFG().getStartBlock();
         assert startBlock != null;
@@ -343,8 +340,8 @@
                 throw Debug.handle(e);
             }
 
-            try (Scope s = Debug.scope("LowLevelTier", nodeLirGen)) {
-                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lowLevelSuites);
+            try (Scope s = Debug.scope("LIRTier", nodeLirGen)) {
+                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
@@ -354,27 +351,30 @@
     }
 
     public static <T extends AbstractBlock<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
-                    LIRGeneratorTool lirGen, LowLevelSuites lowLevelSuites) {
-        LowLevelHighTierContext highTierContext = new LowLevelHighTierContext(lirGen);
-        lowLevelSuites.getHighTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, highTierContext);
+                    LIRGeneratorTool lirGen, LIRSuites lirSuites) {
+        LIRHighTierContext highTierContext = new LIRHighTierContext(lirGen);
+        lirSuites.getHighTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, highTierContext);
 
-        LowLevelMidTierContext midTierContext = new LowLevelMidTierContext();
-        lowLevelSuites.getMidTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, midTierContext);
+        LIRMidTierContext midTierContext = new LIRMidTierContext();
+        lirSuites.getMidTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, midTierContext);
 
-        LowLevelLowTierContext lowTierContext = new LowLevelLowTierContext();
-        lowLevelSuites.getLowTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, lowTierContext);
+        LIRLowTierContext lowTierContext = new LIRLowTierContext();
+        lirSuites.getLowTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, lowTierContext);
 
         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()) {
-            compilationResult.setAssumptions(assumptions);
+        if (assumptions != null && !assumptions.isEmpty()) {
+            compilationResult.setAssumptions(assumptions.toArray());
+        }
+        if (methods != null) {
+            compilationResult.setMethods(methods.toArray(new ResolvedJavaMethod[methods.size()]));
         }
 
         if (Debug.isMeterEnabled()) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.lir.phases.LowLevelHighTierPhase.*;
-import com.oracle.graal.lir.phases.LowLevelLowTierPhase.*;
-import com.oracle.graal.lir.phases.LowLevelMidTierPhase.*;
+import com.oracle.graal.lir.phases.LIRHighTierPhase.*;
+import com.oracle.graal.lir.phases.LIRLowTierPhase.*;
+import com.oracle.graal.lir.phases.LIRMidTierPhase.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -45,16 +45,16 @@
         return new LowTier();
     }
 
-    public LowLevelPhaseSuite<LowLevelHighTierContext> createLowLevelHighTier() {
-        return new LowLevelHighTier();
+    public LIRPhaseSuite<LIRHighTierContext> createLIRHighTier() {
+        return new LIRHighTier();
     }
 
-    public LowLevelPhaseSuite<LowLevelMidTierContext> createLowLevelMidTier() {
-        return new LowLevelMidTier();
+    public LIRPhaseSuite<LIRMidTierContext> createLIRMidTier() {
+        return new LIRMidTier();
     }
 
-    public LowLevelPhaseSuite<LowLevelLowTierContext> createLowLevelLowTier() {
-        return new LowLevelLowTier();
+    public LIRPhaseSuite<LIRLowTierContext> createLIRLowTier() {
+        return new LIRLowTier();
     }
 
 }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Thu Feb 12 20:47:20 2015 +0100
@@ -467,6 +467,10 @@
         log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
     }
 
+    public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
+        log(DEFAULT_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+    }
+
     /**
      * @see #log(int, String, Object)
      */
@@ -476,6 +480,12 @@
         }
     }
 
+    public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) {
+        if (ENABLED) {
+            DebugScope.getInstance().log(logLevel, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+        }
+    }
+
     public static void logv(String format, Object... args) {
         logv(DEFAULT_LOG_LEVEL, format, args);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUnionFind.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2015, 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.graal.graph;
+
+/**
+ * Union-find data structure for {@link Node Nodes}.
+ *
+ * All operations have an accumulated worst-case complexity of O(a(n)), where a(n) is the inverse of
+ * the Ackermann function A(n,n).
+ */
+public class NodeUnionFind extends NodeIdAccessor {
+
+    private int[] rank;
+    private int[] parent;
+
+    /**
+     * Create a new union-find data structure for a {@link Graph}. Initially, all nodes are in their
+     * own equivalence set.
+     */
+    public NodeUnionFind(Graph graph) {
+        super(graph);
+        rank = new int[graph.nodeIdCount()];
+        parent = new int[graph.nodeIdCount()];
+        for (int i = 0; i < parent.length; i++) {
+            parent[i] = i;
+        }
+    }
+
+    /**
+     * Merge the equivalence sets of two nodes.
+     *
+     * After calling this function, find(a) == find(b).
+     */
+    public void union(Node a, Node b) {
+        union(getNodeId(a), getNodeId(b));
+    }
+
+    /**
+     * Get a representative element of the equivalence set of a node.
+     *
+     * This function returns the same representative element for all members of the same equivalence
+     * set, i.e., find(a) == find(b) if and only if a and b are in the same set.
+     */
+    public Node find(Node a) {
+        int id = find(getNodeId(a));
+        return graph.getNode(id);
+    }
+
+    public boolean equiv(Node a, Node b) {
+        return find(getNodeId(a)) == find(getNodeId(b));
+    }
+
+    private void union(int a, int b) {
+        int aRoot = find(a);
+        int bRoot = find(b);
+        if (rank[aRoot] < rank[bRoot]) {
+            parent[aRoot] = bRoot;
+        } else {
+            parent[bRoot] = aRoot;
+            if (rank[aRoot] == rank[bRoot]) {
+                rank[aRoot]++;
+            }
+        }
+    }
+
+    private int find(int a) {
+        int ret = a;
+        while (ret != parent[ret]) {
+            parent[ret] = parent[parent[ret]];
+            ret = parent[ret];
+        }
+        return ret;
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/CanonicalizerTool.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/CanonicalizerTool.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,13 +22,10 @@
  */
 package com.oracle.graal.graph.spi;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 
 public interface CanonicalizerTool {
 
-    Assumptions assumptions();
-
     MetaAccessProvider getMetaAccess();
 
     ConstantReflectionProvider getConstantReflection();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Thu Feb 12 20:47:20 2015 +0100
@@ -152,15 +152,12 @@
             try (InitTimer rt = timer("create Lowerer provider")) {
                 lowerer = createLowerer(runtime, metaAccess, foreignCalls, registers, target);
             }
-            // Replacements cannot have speculative optimizations since they have
-            // to be valid for the entire run of the VM.
-            Assumptions assumptions = new Assumptions(false);
             Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, new HotSpotStampProvider());
             try (InitTimer rt = timer("create SnippetReflection provider")) {
                 snippetReflection = createSnippetReflection(runtime);
             }
             try (InitTimer rt = timer("create Replacements provider")) {
-                replacements = createReplacements(runtime, assumptions, p, snippetReflection);
+                replacements = createReplacements(runtime, p, snippetReflection);
             }
             try (InitTimer rt = timer("create Disassembler provider")) {
                 disassembler = createDisassembler(runtime);
@@ -187,8 +184,8 @@
         return new HotSpotDisassemblerProvider(runtime);
     }
 
-    protected Replacements createReplacements(HotSpotGraalRuntimeProvider runtime, Assumptions assumptions, Providers p, SnippetReflectionProvider snippetReflection) {
-        return new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), assumptions, p.getCodeCache().getTarget());
+    protected Replacements createReplacements(HotSpotGraalRuntimeProvider runtime, Providers p, SnippetReflectionProvider snippetReflection) {
+        return new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), p.getCodeCache().getTarget());
     }
 
     protected AMD64HotSpotForeignCallsProvider createForeignCalls(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache,
@@ -251,15 +248,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             *
+             * 
              * Draft Version 0.96
-             *
+             * 
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             *
+             * 
              * 3.2.1
-             *
+             * 
              * ...
-             *
+             * 
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Thu Feb 12 20:47:20 2015 +0100
@@ -60,12 +60,9 @@
         Value[] nativeABICallerSaveRegisters = createNativeABICallerSaveRegisters(runtime.getConfig(), codeCache.getRegisterConfig());
         HotSpotForeignCallsProvider foreignCalls = new SPARCHotSpotForeignCallsProvider(runtime, metaAccess, codeCache, nativeABICallerSaveRegisters);
         LoweringProvider lowerer = new SPARCHotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, target);
-        // Replacements cannot have speculative optimizations since they have
-        // to be valid for the entire run of the VM.
-        Assumptions assumptions = new Assumptions(false);
         Providers p = new Providers(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, null, new HotSpotStampProvider());
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime);
-        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), assumptions, target);
+        HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), target);
         HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
         HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -41,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;
@@ -204,7 +205,7 @@
     }
 
     private StructuredGraph compile(String test, boolean compileAOT) {
-        StructuredGraph graph = parseEager(test);
+        StructuredGraph graph = parseEager(test, AllowAssumptions.YES);
         ResolvedJavaMethod method = graph.method();
 
         try (OverrideScope s = OptionValue.override(ImmutableCode, compileAOT)) {
@@ -212,10 +213,9 @@
             // create suites everytime, as we modify options for the compiler
             SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
             final Suites suitesLocal = suitesProvider.createSuites();
-            final LowLevelSuites lowLevelSuitesLocal = suitesProvider.createLowLevelSuites();
+            final LIRSuites lirSuitesLocal = suitesProvider.createLIRSuites();
             final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                            OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, lowLevelSuitesLocal, new CompilationResult(),
-                            CompilationResultBuilderFactory.Default);
+                            OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, lirSuitesLocal, new CompilationResult(), CompilationResultBuilderFactory.Default);
             addMethod(method, compResult);
         }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Thu Feb 12 20:47:20 2015 +0100
@@ -32,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 {
 
@@ -43,7 +44,7 @@
 
     protected StructuredGraph test(final String snippet) {
         try (Scope s = Debug.scope("ClassSubstitutionsTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) {
-            StructuredGraph graph = parseEager(snippet);
+            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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,6 +28,7 @@
 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 {
 
@@ -36,7 +37,7 @@
     @Test
     public void testInstallCodeInvalidation() {
         final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
-        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo"));
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
         Assert.assertTrue(nmethod.isValid());
         Object result;
         try {
@@ -59,7 +60,7 @@
     @Test
     public void testInstallCodeInvalidationWhileRunning() {
         final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
-        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo"));
+        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo", AllowAssumptions.YES));
         Object result;
         try {
             result = nmethod.executeVarargs(nmethod, null, null);
@@ -73,7 +74,7 @@
     @Test
     public void testInstalledCodeCalledFromCompiledCode() {
         final ResolvedJavaMethod testJavaMethod = getResolvedJavaMethod("foo");
-        final HotSpotNmethod nmethod = (HotSpotNmethod) getCode(testJavaMethod, parseEager("otherFoo"));
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeSubstitutionsTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.replacements.test.*;
 
 /**
@@ -35,7 +36,7 @@
 
     @Test
     public void test() {
-        StructuredGraph graph = new StructuredGraph();
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java	Thu Feb 12 20:47:20 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) {
-        StructuredGraph graph = super.parseEager(m);
+    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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,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.*;
 
 /**
@@ -134,10 +135,10 @@
         method.reprofile();
 
         int id = method.allocateCompileId(INVOCATION_ENTRY_BCI);
-        long ctask = 0L;
+        long graalEnv = 0L;
 
         try (MemoryUsageCloseable c = label == null ? null : new MemoryUsageCloseable(label)) {
-            CompilationTask task = new CompilationTask(backend, method, INVOCATION_ENTRY_BCI, ctask, id, false);
+            CompilationTask task = new CompilationTask(backend, method, INVOCATION_ENTRY_BCI, graalEnv, id, false);
             task.runCompilation();
         }
     }
@@ -151,9 +152,9 @@
             method.reprofile();
 
             int id = method.allocateCompileId(INVOCATION_ENTRY_BCI);
-            long ctask = 0L;
+            long graalEnv = 0L;
             try (AllocSpy as = AllocSpy.open(methodName)) {
-                CompilationTask task = new CompilationTask(backend, method, INVOCATION_ENTRY_BCI, ctask, id, false);
+                CompilationTask task = new CompilationTask(backend, method, INVOCATION_ENTRY_BCI, graalEnv, id, false);
                 task.runCompilation();
             }
         }
@@ -164,7 +165,7 @@
     private void compileAndTime(String methodName) {
 
         // Parse in eager mode to resolve methods/fields/classes
-        parseEager(methodName);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,7 +26,6 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.test.*;
@@ -39,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.*;
@@ -244,9 +244,9 @@
     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);
-            HighTierContext highContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
-            MidTierContext midContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+            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);
             new InliningPhase(new InlineEverythingPolicy(), new CanonicalizerPhase(true)).apply(graph, highContext);
             new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highContext);
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,7 +26,6 @@
 
 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.debug.*;
@@ -37,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.*;
@@ -626,11 +626,11 @@
 
     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);
-            HighTierContext highTierContext = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+            final StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+            HighTierContext highTierContext = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
             new InliningPhase(new CanonicalizerPhase(true)).apply(graph, highTierContext);
 
-            MidTierContext midTierContext = new MidTierContext(getProviders(), new Assumptions(false), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
+            MidTierContext midTierContext = new MidTierContext(getProviders(), getCodeCache().getTarget(), OptimisticOptimizations.ALL, graph.method().getProfilingInfo(), null);
 
             new LoweringPhase(new CanonicalizerPhase(true), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
             new GuardLoweringPhase().apply(graph, midTierContext);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Thu Feb 12 20:47:20 2015 +0100
@@ -97,17 +97,16 @@
     private static final com.sun.management.ThreadMXBean threadMXBean = (com.sun.management.ThreadMXBean) ManagementFactory.getThreadMXBean();
 
     /**
-     * The address of the native CompileTask associated with this compilation or 0L if no such
-     * association exists.
+     * The address of the GraalEnv associated with this compilation or 0L if no such object exists.
      */
-    private final long ctask;
+    private final long graalEnv;
 
-    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long ctask, int id, boolean installAsDefault) {
+    public CompilationTask(HotSpotBackend backend, HotSpotResolvedJavaMethod method, int entryBCI, long graalEnv, int id, boolean installAsDefault) {
         this.backend = backend;
         this.method = method;
         this.entryBCI = entryBCI;
         this.id = id;
-        this.ctask = ctask;
+        this.graalEnv = graalEnv;
         this.installAsDefault = installAsDefault;
     }
 
@@ -139,8 +138,8 @@
         return providers.getSuites().getDefaultSuites();
     }
 
-    protected LowLevelSuites getLowLevelSuites(HotSpotProviders providers) {
-        return providers.getSuites().getDefaultLowLevelSuites();
+    protected LIRSuites getLIRSuites(HotSpotProviders providers) {
+        return providers.getSuites().getDefaultLIRSuites();
     }
 
     protected PhaseSuite<HighTierContext> getGraphBuilderSuite(HotSpotProviders providers) {
@@ -209,14 +208,19 @@
                         graphCache = new HashMap<>();
                     }
 
+                    boolean recordEvolMethodDeps = graalEnv == 0 || unsafe.getByte(graalEnv + config.graalEnvJvmtiCanHotswapOrPostBreakpointOffset) != 0;
+
                     HotSpotProviders providers = backend.getProviders();
                     Replacements replacements = providers.getReplacements();
                     graph = replacements.getMethodSubstitution(method);
                     if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
-                        graph = new StructuredGraph(method, entryBCI);
+                        graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
+                        if (!recordEvolMethodDeps) {
+                            graph.disableMethodRecording();
+                        }
                     } else {
                         // Compiling method substitution - must clone the graph
-                        graph = graph.copy();
+                        graph = graph.copy(graph.name, method, AllowAssumptions.from(OptAssumptions.getValue()), recordEvolMethodDeps);
                     }
                     InlinedBytecodes.add(method.getCodeSize());
                     CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
@@ -228,7 +232,7 @@
                         cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
                     }
                     Suites suites = getSuites(providers);
-                    LowLevelSuites lowLevelSuites = getLowLevelSuites(providers);
+                    LIRSuites lirSuites = getLIRSuites(providers);
                     ProfilingInfo profilingInfo = getProfilingInfo();
                     OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
                     if (isOSR) {
@@ -237,7 +241,7 @@
                         optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
                     }
                     result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
-                                    method.getSpeculationLog(), suites, lowLevelSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
+                                    method.getSpeculationLog(), suites, lirSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
                 }
                 result.setId(getId());
                 result.setEntryBCI(entryBCI);
@@ -313,7 +317,9 @@
                 compilationEvent.commit();
             }
 
-            if (ctask != 0) {
+            if (graalEnv != 0) {
+                long ctask = unsafe.getAddress(graalEnv + config.graalEnvTaskOffset);
+                assert ctask != 0L;
                 unsafe.putInt(ctask + config.compileTaskNumInlinedBytecodesOffset, processedBytes);
             }
             if ((config.ciTime || config.ciTimeEach) && installedCode != null) {
@@ -335,7 +341,7 @@
         final HotSpotCodeCacheProvider codeCache = backend.getProviders().getCodeCache();
         InstalledCode installedCode = null;
         try (Scope s = Debug.scope("CodeInstall", new DebugDumpScope(String.valueOf(id), true), codeCache, method)) {
-            installedCode = codeCache.installMethod(method, compResult, ctask, installAsDefault);
+            installedCode = codeCache.installMethod(method, compResult, graalEnv, installAsDefault);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -354,11 +360,11 @@
      *
      * @param metaspaceMethod
      * @param entryBCI
-     * @param ctask address of native CompileTask object
+     * @param graalEnv address of native GraalEnv object
      * @param id CompileTask::_compile_id
      */
     @SuppressWarnings("unused")
-    private static void compileMetaspaceMethod(long metaspaceMethod, int entryBCI, long ctask, int id) {
+    private static void compileMetaspaceMethod(long metaspaceMethod, int entryBCI, long graalEnv, int id) {
         // Ensure a Graal runtime is initialized prior to Debug being initialized as the former
         // may include processing command line options used by the latter.
         Graal.getRuntime();
@@ -369,15 +375,15 @@
         }
 
         HotSpotResolvedJavaMethod method = HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod);
-        compileMethod(method, entryBCI, ctask, id);
+        compileMethod(method, entryBCI, graalEnv, id);
     }
 
     /**
      * Compiles a method to machine code.
      */
-    static void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long ctask, int id) {
+    static void compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long graalEnv, int id) {
         HotSpotBackend backend = runtime().getHostBackend();
-        CompilationTask task = new CompilationTask(backend, method, entryBCI, ctask, id, true);
+        CompilationTask task = new CompilationTask(backend, method, entryBCI, graalEnv, id, true);
         try (DebugConfigScope dcs = setConfig(new TopLevelDebugConfig())) {
             task.runCompilation();
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,17 +34,22 @@
     public final HotSpotResolvedJavaMethod method;
     public final int entryBCI;
     public final int id;
-    public final long ctask;
+    public final long graalEnv;
 
     public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult) {
         this(method, compResult, 0L);
     }
 
-    public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask) {
+    public HotSpotCompiledNmethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long graalEnv) {
         super(compResult);
         this.method = method;
         this.entryBCI = compResult.getEntryBCI();
         this.id = compResult.getId();
-        this.ctask = ctask;
+        this.graalEnv = graalEnv;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + "[" + id + ":" + method.format("%H.%n(%p)%r@") + entryBCI + "]";
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Thu Feb 12 20:47:20 2015 +0100
@@ -51,7 +51,13 @@
      * Checks the conditions a compilation must satisfy to be installed as a RuntimeStub.
      */
     private boolean checkStubInvariants(CompilationResult compResult) {
-        assert compResult.getExceptionHandlers().isEmpty();
+        assert compResult.getExceptionHandlers().isEmpty() : this;
+
+        // Stubs cannot be recompiled so they cannot be compiled with
+        // assumptions and there is no point in recording evol_method dependencies
+        assert compResult.getAssumptions().isEmpty() : "stubs should not use assumptions: " + this;
+        assert compResult.getMethods().isEmpty() : "stubs should not record evol_method dependencies: " + this;
+
         for (DataPatch data : compResult.getDataPatches()) {
             if (data.reference instanceof ConstantReference) {
                 ConstantReference ref = (ConstantReference) data.reference;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Thu Feb 12 20:47:20 2015 +0100
@@ -69,10 +69,7 @@
         try (InitTimer st = timer("graphBuilderPlugins.initialize")) {
             GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
             GraphBuilderPlugins plugins = phase.getGraphBuilderPlugins();
-            Iterable<GraphBuilderPluginsProvider> sl = Services.load(GraphBuilderPluginsProvider.class);
-            for (GraphBuilderPluginsProvider p : sl) {
-                p.registerPlugins(providers.getMetaAccess(), plugins);
-            }
+            registerGraphBuilderPlugins(providers.getMetaAccess(), plugins);
         }
 
         try (InitTimer st = timer("foreignCalls.initialize")) {
@@ -103,4 +100,9 @@
             }
         }
     }
+
+    protected void registerGraphBuilderPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        StandardGraphBuilderPlugins.registerPlugins(metaAccess, plugins);
+        HotSpotGraphBuilderPlugins.registerPlugins(metaAccess, plugins);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -44,8 +44,8 @@
 
     private final HotSpotVMConfig config;
 
-    public HotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, HotSpotVMConfig config, Assumptions assumptions, TargetDescription target) {
-        super(providers, snippetReflection, assumptions, target);
+    public HotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, HotSpotVMConfig config, TargetDescription target) {
+        super(providers, snippetReflection, target);
         this.config = config;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Thu Feb 12 20:47:20 2015 +0100
@@ -1082,6 +1082,8 @@
     @HotSpotVMConstant(name = "JVM_ACC_MONITOR_MATCH") @Stable public int jvmAccMonitorMatch;
     @HotSpotVMConstant(name = "JVM_ACC_HAS_MONITOR_BYTECODES") @Stable public int jvmAccHasMonitorBytecodes;
 
+    @HotSpotVMField(name = "GraalEnv::_task", type = "CompileTask*", get = HotSpotVMField.Type.OFFSET) @Stable public int graalEnvTaskOffset;
+    @HotSpotVMField(name = "GraalEnv::_jvmti_can_hotswap_or_post_breakpoint", type = "bool", get = HotSpotVMField.Type.OFFSET) @Stable public int graalEnvJvmtiCanHotswapOrPostBreakpointOffset;
     @HotSpotVMField(name = "CompileTask::_num_inlined_bytecodes", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int compileTaskNumInlinedBytecodesOffset;
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Thu Feb 12 20:47:20 2015 +0100
@@ -239,12 +239,12 @@
         return installedCode;
     }
 
-    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long ctask, boolean isDefault) {
+    public InstalledCode installMethod(HotSpotResolvedJavaMethod method, CompilationResult compResult, long graalEnv, boolean isDefault) {
         if (compResult.getId() == -1) {
             compResult.setId(method.allocateCompileId(compResult.getEntryBCI()));
         }
         HotSpotInstalledCode installedCode = new HotSpotNmethod(method, compResult.getName(), isDefault);
-        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(method, compResult, ctask), installedCode, method.getSpeculationLog());
+        runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(method, compResult, graalEnv), installedCode, method.getSpeculationLog());
         return logOrDump(installedCode, compResult);
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,104 @@
+/*
+ * 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.graal.hotspot.meta;
+
+import static com.oracle.graal.java.GraphBuilderContext.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.options.*;
+
+/**
+ * Provider of HotSpot specific {@link GraphBuilderPlugin}s.
+ */
+public class HotSpotGraphBuilderPlugins {
+    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        // Object.class
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("getClass", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
+                ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
+                ValueNode mirror;
+                if (objectStamp.isExactType() && objectStamp.nonNull()) {
+                    mirror = builder.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), builder.getMetaAccess()));
+                } else {
+                    StampProvider stampProvider = builder.getStampProvider();
+                    LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, nullCheckedValue(builder, rcvr)));
+                    mirror = builder.append(new HubGetClassNode(builder.getMetaAccess(), hub));
+                }
+                builder.push(Kind.Object, mirror);
+                return true;
+            }
+        });
+
+        // Class.class
+        r = new Registration(plugins, metaAccess, Class.class);
+        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr, ValueNode object) {
+                if (rcvr.isConstant() && !rcvr.isNullConstant() && object.isConstant()) {
+                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
+                    if (type != null && !type.isPrimitive() && type.isInstance(object.asJavaConstant())) {
+                        builder.push(Kind.Object, object);
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
+        r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr, ValueNode object) {
+                if (rcvr.isConstant() && !rcvr.isNullConstant() && object.isConstant()) {
+                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
+                    if (type != null && !type.isPrimitive()) {
+                        builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(type.isInstance(object.asJavaConstant()))));
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
+
+        // StableOptionValue.class
+        r = new Registration(plugins, metaAccess, StableOptionValue.class);
+        r.register1("getValue", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
+                if (rcvr.isConstant() && !rcvr.isNullConstant()) {
+                    Object object = ((HotSpotObjectConstantImpl) rcvr.asConstant()).object();
+                    StableOptionValue<?> option = (StableOptionValue<?>) object;
+                    ConstantNode value = builder.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), builder.getMetaAccess()));
+                    builder.push(Kind.Object, value);
+                    return true;
+                }
+                return false;
+            }
+        });
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPluginsProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * 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.graal.hotspot.meta;
-
-import static com.oracle.graal.java.GraphBuilderContext.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.options.*;
-
-/**
- * Provider of HotSpot specific {@link GraphBuilderPlugin}s.
- */
-@ServiceProvider(GraphBuilderPluginsProvider.class)
-public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
-    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        // Object.class
-        Registration r = new Registration(plugins, metaAccess, Object.class);
-        r.register1("getClass", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
-                ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
-                ValueNode mirror;
-                if (objectStamp.isExactType() && objectStamp.nonNull()) {
-                    mirror = builder.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), builder.getMetaAccess()));
-                } else {
-                    StampProvider stampProvider = builder.getStampProvider();
-                    LoadHubNode hub = builder.append(new LoadHubNode(stampProvider, nullCheckedValue(builder, rcvr)));
-                    mirror = builder.append(new HubGetClassNode(builder.getMetaAccess(), hub));
-                }
-                builder.push(Kind.Object, mirror);
-                return true;
-            }
-        });
-
-        // Class.class
-        r = new Registration(plugins, metaAccess, Class.class);
-        r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode rcvr, ValueNode object) {
-                if (rcvr.isConstant() && !rcvr.isNullConstant() && object.isConstant()) {
-                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
-                    if (type != null && !type.isPrimitive() && type.isInstance(object.asJavaConstant())) {
-                        builder.push(Kind.Object, object);
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
-        r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode rcvr, ValueNode object) {
-                if (rcvr.isConstant() && !rcvr.isNullConstant() && object.isConstant()) {
-                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
-                    if (type != null && !type.isPrimitive()) {
-                        builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(type.isInstance(object.asJavaConstant()))));
-                        return true;
-                    }
-                }
-                return false;
-            }
-        });
-
-        // StableOptionValue.class
-        r = new Registration(plugins, metaAccess, StableOptionValue.class);
-        r.register1("getValue", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode rcvr) {
-                if (rcvr.isConstant() && !rcvr.isNullConstant()) {
-                    Object object = ((HotSpotObjectConstantImpl) rcvr.asConstant()).object();
-                    StableOptionValue<?> option = (StableOptionValue<?>) object;
-                    ConstantNode value = builder.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), builder.getMetaAccess()));
-                    builder.push(Kind.Object, value);
-                    return true;
-                }
-                return false;
-            }
-        });
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Thu Feb 12 20:47:20 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/meta/HotSpotSuitesProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Thu Feb 12 20:47:20 2015 +0100
@@ -45,7 +45,7 @@
 
     protected final DerivedOptionValue<Suites> defaultSuites;
     protected final PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
-    private final DerivedOptionValue<LowLevelSuites> defaultLowLevelSuites;
+    private final DerivedOptionValue<LIRSuites> defaultLIRSuites;
     protected final HotSpotGraalRuntimeProvider runtime;
 
     private class SuitesSupplier implements OptionSupplier<Suites> {
@@ -58,12 +58,12 @@
 
     }
 
-    private class LowLevelSuitesSupplier implements OptionSupplier<LowLevelSuites> {
+    private class LIRSuitesSupplier implements OptionSupplier<LIRSuites> {
 
         private static final long serialVersionUID = -1558586374095874299L;
 
-        public LowLevelSuites get() {
-            return createLowLevelSuites();
+        public LIRSuites get() {
+            return createLIRSuites();
         }
 
     }
@@ -72,7 +72,7 @@
         this.runtime = runtime;
         this.defaultGraphBuilderSuite = createGraphBuilderSuite();
         this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
-        this.defaultLowLevelSuites = new DerivedOptionValue<>(new LowLevelSuitesSupplier());
+        this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
 
     public Suites getDefaultSuites() {
@@ -135,12 +135,12 @@
         return gbs;
     }
 
-    public LowLevelSuites getDefaultLowLevelSuites() {
-        return defaultLowLevelSuites.getValue();
+    public LIRSuites getDefaultLIRSuites() {
+        return defaultLIRSuites.getValue();
     }
 
-    public LowLevelSuites createLowLevelSuites() {
-        return Suites.createDefaultLowLevelSuites();
+    public LIRSuites createLIRSuites() {
+        return Suites.createDefaultLIRSuites();
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Thu Feb 12 20:47:20 2015 +0100
@@ -161,11 +161,11 @@
     private InstalledCode installNativeFunctionStub(long functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
         StructuredGraph g = getGraph(providers, factory, functionPointer, returnType, argumentTypes);
         Suites suites = providers.getSuites().createSuites();
-        LowLevelSuites lowLevelSuites = providers.getSuites().createLowLevelSuites();
+        LIRSuites lirSuites = providers.getSuites().createLIRSuites();
         PhaseSuite<HighTierContext> phaseSuite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, g.method(), false);
         CompilationResult compResult = GraalCompiler.compileGraph(g, cc, g.method(), providers, backend, backend.getTarget(), null, phaseSuite, OptimisticOptimizations.ALL,
-                        DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, lowLevelSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        DefaultProfilingInfo.get(TriState.UNKNOWN), null, suites, lirSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
         InstalledCode installedCode;
         try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache(), g.method())) {
             installedCode = providers.getCodeCache().addMethod(g.method(), compResult, null, null);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Thu Feb 12 20:47:20 2015 +0100
@@ -32,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.*;
@@ -52,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);
+            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/CallSiteTargetNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -43,10 +42,10 @@
         return arguments.get(0);
     }
 
-    private ConstantNode getConstantCallTarget(MetaAccessProvider metaAccess, Assumptions assumptions) {
+    private ConstantNode getConstantCallTarget(MetaAccessProvider metaAccess) {
         if (getCallSite().isConstant() && !getCallSite().isNullConstant()) {
             HotSpotObjectConstant c = (HotSpotObjectConstant) getCallSite().asConstant();
-            JavaConstant target = c.getCallSiteTarget(assumptions);
+            JavaConstant target = c.getCallSiteTarget(graph().getAssumptions());
             if (target != null) {
                 return ConstantNode.forConstant(target, metaAccess);
             }
@@ -56,7 +55,7 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ConstantNode target = getConstantCallTarget(tool.getMetaAccess(), tool.assumptions());
+        ConstantNode target = getConstantCallTarget(tool.getMetaAccess());
         if (target != null) {
             return target;
         }
@@ -66,7 +65,7 @@
 
     @Override
     public void lower(LoweringTool tool) {
-        ConstantNode target = getConstantCallTarget(tool.getMetaAccess(), tool.assumptions());
+        ConstantNode target = getConstantCallTarget(tool.getMetaAccess());
 
         if (target != null) {
             graph().replaceFixedWithFloating(this, target);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Thu Feb 12 20:47:20 2015 +0100
@@ -226,7 +226,8 @@
             if (replacer.instanceOf instanceof InstanceOfNode) {
                 InstanceOfNode instanceOf = (InstanceOfNode) replacer.instanceOf;
                 ValueNode object = instanceOf.getValue();
-                TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), tool.assumptions(), TypeCheckMinProfileHitProbability.getValue(), TypeCheckMaxHints.getValue());
+                Assumptions assumptions = instanceOf.graph().getAssumptions();
+                TypeCheckHints hintInfo = new TypeCheckHints(instanceOf.type(), instanceOf.profile(), assumptions, TypeCheckMinProfileHitProbability.getValue(), TypeCheckMaxHints.getValue());
                 final HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) instanceOf.type();
                 ConstantNode hub = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), type.klass(), providers.getMetaAccess(), instanceOf.graph());
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,11 +26,13 @@
 
 import java.lang.reflect.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 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.*;
@@ -68,9 +70,10 @@
                 }
                 assert false : "unhandled array type " + type.getComponentType().getKind();
             } else {
-                type = getConcreteType(getObject().stamp(), tool.assumptions(), tool.getMetaAccess());
+                Assumptions assumptions = graph().getAssumptions();
+                type = getConcreteType(getObject().stamp(), assumptions, tool.getMetaAccess());
                 if (type != null) {
-                    StructuredGraph newGraph = new StructuredGraph();
+                    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/replacements/arraycopy/ArrayCopyNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -73,7 +73,7 @@
         }
         // the canonicalization before loop unrolling is needed to propagate the length into
         // additions, etc.
-        PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.assumptions(), tool.getStampProvider());
+        PhaseContext context = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider());
         new CanonicalizerPhase(true).apply(snippetGraph, context);
         new LoopFullUnrollPhase(new CanonicalizerPhase(true)).apply(snippetGraph, context);
         new CanonicalizerPhase(true).apply(snippetGraph, context);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Thu Feb 12 20:47:20 2015 +0100
@@ -36,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.*;
@@ -190,7 +191,8 @@
         Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
         boolean isObjectResult = linkage.getOutgoingCallingConvention().getReturn().getKind() == Kind.Object;
 
-        StructuredGraph graph = new StructuredGraph(toString(), null);
+        StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO);
+        graph.disableMethodRecording();
 
         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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Thu Feb 12 20:47:20 2015 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.hotspot.stubs;
 
 import static com.oracle.graal.compiler.GraalCompiler.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
 
 import java.util.*;
@@ -158,6 +157,12 @@
         if (code == null) {
             try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) {
                 final StructuredGraph graph = getGraph();
+
+                // Stubs cannot be recompiled so they cannot be compiled with
+                // assumptions and there is no point in recording evol_method dependencies
+                assert graph.getAssumptions() == null;
+                assert !graph.isMethodRecordingEnabled() : graph;
+
                 if (!(graph.start() instanceof StubStartNode)) {
                     StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
                     newStart.setStateAfter(graph.start().stateAfter());
@@ -171,14 +176,12 @@
 
                 compResult = new CompilationResult(toString());
                 try (Scope s0 = Debug.scope("StubCompilation", graph, providers.getCodeCache())) {
-                    Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
                     Suites defaultSuites = providers.getSuites().getDefaultSuites();
                     Suites suites = new Suites(new PhaseSuite<>(), defaultSuites.getMidTier(), defaultSuites.getLowTier());
-                    SchedulePhase schedule = emitFrontEnd(providers, target, graph, assumptions, null, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
-                                    getProfilingInfo(graph), null, suites);
-                    LowLevelSuites lowLevelSuites = providers.getSuites().getDefaultLowLevelSuites();
-                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, assumptions, schedule,
-                                    getRegisterConfig(), lowLevelSuites);
+                    SchedulePhase schedule = emitFrontEnd(providers, target, graph, null, providers.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graph),
+                                    null, suites);
+                    LIRSuites lirSuites = providers.getSuites().getDefaultLIRSuites();
+                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, schedule, getRegisterConfig(), lirSuites);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java	Thu Feb 12 20:47:20 2015 +0100
@@ -55,6 +55,12 @@
         return plugins.get(method);
     }
 
+    public DefaultGraphBuilderPlugins copy() {
+        DefaultGraphBuilderPlugins result = new DefaultGraphBuilderPlugins();
+        result.plugins.putAll(plugins);
+        return result;
+    }
+
     @Override
     public String toString() {
         return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Thu Feb 12 20:47:20 2015 +0100
@@ -32,7 +32,7 @@
 
     private final DerivedOptionValue<Suites> defaultSuites;
     private final PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
-    private final DerivedOptionValue<LowLevelSuites> defaultLowLevelSuites;
+    private final DerivedOptionValue<LIRSuites> defaultLIRSuites;
 
     private class SuitesSupplier implements OptionSupplier<Suites> {
 
@@ -44,12 +44,12 @@
 
     }
 
-    private class LowLevelSuitesSupplier implements OptionSupplier<LowLevelSuites> {
+    private class LIRSuitesSupplier implements OptionSupplier<LIRSuites> {
 
         private static final long serialVersionUID = 312070237227476252L;
 
-        public LowLevelSuites get() {
-            return createLowLevelSuites();
+        public LIRSuites get() {
+            return createLIRSuites();
         }
 
     }
@@ -57,7 +57,7 @@
     public DefaultSuitesProvider() {
         this.defaultGraphBuilderSuite = createGraphBuilderSuite();
         this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
-        this.defaultLowLevelSuites = new DerivedOptionValue<>(new LowLevelSuitesSupplier());
+        this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
 
     public Suites getDefaultSuites() {
@@ -78,12 +78,12 @@
         return suite;
     }
 
-    public LowLevelSuites getDefaultLowLevelSuites() {
-        return defaultLowLevelSuites.getValue();
+    public LIRSuites getDefaultLIRSuites() {
+        return defaultLIRSuites.getValue();
     }
 
-    public LowLevelSuites createLowLevelSuites() {
-        return Suites.createDefaultLowLevelSuites();
+    public LIRSuites createLIRSuites() {
+        return Suites.createDefaultLIRSuites();
     }
 
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -78,8 +78,7 @@
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), null, context.getConstantReflection(), graphBuilderConfig, graphBuilderPlugins,
-                        context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), null, context.getConstantReflection(), graphBuilderConfig, graphBuilderPlugins, context.getOptimisticOptimizations()).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
@@ -102,7 +101,6 @@
         private final GraphBuilderPlugins graphBuilderPlugins;
         private final OptimisticOptimizations optimisticOpts;
         private final StampProvider stampProvider;
-        private final Assumptions assumptions;
         private final ConstantReflectionProvider constantReflection;
         private final SnippetReflectionProvider snippetReflectionProvider;
 
@@ -113,22 +111,21 @@
             return currentGraph;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, SnippetReflectionProvider snippetReflectionProvider,
-                        ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) {
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection,
+                        GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
-            this.assumptions = assumptions;
             this.graphBuilderPlugins = graphBuilderPlugins;
             this.constantReflection = constantReflection;
             this.snippetReflectionProvider = snippetReflectionProvider;
             assert metaAccess != null;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
-            this(metaAccess, stampProvider, assumptions, null, constantReflection, graphBuilderConfig, null, optimisticOpts);
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
+                        OptimisticOptimizations optimisticOpts) {
+            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, null, optimisticOpts);
         }
 
         @Override
@@ -836,7 +833,7 @@
                 InvokeKind invokeKind = initialInvokeKind;
                 if (initialInvokeKind.isIndirect()) {
                     ResolvedJavaType contextType = this.frameState.method.getDeclaringClass();
-                    ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(initialInvokeKind, args[0], initialTargetMethod, assumptions, contextType);
+                    ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(initialInvokeKind, args[0], initialTargetMethod, contextType);
                     if (specialCallTarget != null) {
                         invokeKind = InvokeKind.Special;
                         targetMethod = specialCallTarget;
@@ -973,6 +970,11 @@
                     }
                     calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
                 }
+
+                // Record method dependency in the graph
+                if (currentGraph.isMethodRecordingEnabled()) {
+                    currentGraph.getMethods().add(targetMethod);
+                }
             }
 
             protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType) {
@@ -1691,7 +1693,7 @@
             }
 
             public Assumptions getAssumptions() {
-                return assumptions;
+                return currentGraph.getAssumptions();
             }
 
             public void push(Kind kind, ValueNode value) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Thu Feb 12 20:47:20 2015 +0100
@@ -27,7 +27,6 @@
  *
  * Concrete plugins implement one of the sub-interfaces of this interface.
  *
- * @see GraphBuilderPluginsProvider
  * @see GraphBuilderPlugins
  * @see GraphBuilderPlugins.Registration
  */
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Thu Feb 12 20:47:20 2015 +0100
@@ -296,4 +296,6 @@
      * @return the plugin associated with {@code method} or {@code null} if none exists
      */
     InvocationPlugin lookupInvocation(ResolvedJavaMethod method);
+
+    DefaultGraphBuilderPlugins copy();
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * 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.graal.java;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
-
-/**
- * Interface for providers of {@link GraphBuilderPlugin}s.
- */
-public interface GraphBuilderPluginsProvider extends Service {
-    /**
-     * Registers the plugins provided by this object.
-     */
-    void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPlugins.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,100 @@
+/*
+ * 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.graal.java;
+
+import static com.oracle.graal.java.GraphBuilderContext.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration;
+import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+
+/**
+ * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
+ */
+public class StandardGraphBuilderPlugins {
+    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Object.class);
+        r.register1("<init>", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode object) {
+                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
+                    builder.append(new RegisterFinalizerNode(object));
+                }
+                return true;
+            }
+        });
+
+        for (Kind kind : Kind.values()) {
+            if (kind.isPrimitive() && kind != Kind.Void) {
+                new BoxPlugin(kind).register(metaAccess, plugins);
+                new UnboxPlugin(kind).register(metaAccess, plugins);
+            }
+        }
+
+        GraalDirectivePlugins.registerPlugins(metaAccess, plugins);
+    }
+
+    static class BoxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        BoxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
+            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnboxPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+
+        UnboxPlugin(Kind kind) {
+            this.kind = kind;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode value) {
+            ValueNode valueNode = UnboxNode.create(builder.getMetaAccess(), builder.getConstantReflection(), nullCheckedValue(builder, value), kind);
+            builder.push(kind.getStackKind(), builder.append(valueNode));
+            return true;
+        }
+
+        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
+            plugins.register(method, this);
+        }
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * 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.graal.java;
-
-import static com.oracle.graal.java.GraphBuilderContext.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
- */
-@ServiceProvider(GraphBuilderPluginsProvider.class)
-public class StandardGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
-    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Object.class);
-        r.register1("<init>", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode object) {
-                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
-                    builder.append(new RegisterFinalizerNode(object));
-                }
-                return true;
-            }
-        });
-
-        for (Kind kind : Kind.values()) {
-            if (kind.isPrimitive() && kind != Kind.Void) {
-                new BoxPlugin(kind).register(metaAccess, plugins);
-                new UnboxPlugin(kind).register(metaAccess, plugins);
-            }
-        }
-
-        GraalDirectivePlugins.registerPlugins(metaAccess, plugins);
-    }
-
-    static class BoxPlugin implements InvocationPlugin {
-
-        private final Kind kind;
-
-        BoxPlugin(Kind kind) {
-            this.kind = kind;
-        }
-
-        public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
-            return true;
-        }
-
-        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
-            plugins.register(method, this);
-        }
-    }
-
-    static class UnboxPlugin implements InvocationPlugin {
-
-        private final Kind kind;
-
-        UnboxPlugin(Kind kind) {
-            this.kind = kind;
-        }
-
-        public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ValueNode valueNode = UnboxNode.create(builder.getMetaAccess(), builder.getConstantReflection(), nullCheckedValue(builder, value), kind);
-            builder.push(kind.getStackKind(), builder.append(valueNode));
-            return true;
-        }
-
-        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-            String name = kind.toJavaClass().getSimpleName() + "Value";
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
-            plugins.register(method, this);
-        }
-    }
-}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Thu Feb 12 20:47:20 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) {
-        StructuredGraph graph = super.parseEager(m);
+    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.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Thu Feb 12 20:47:20 2015 +0100
@@ -35,7 +35,7 @@
 /**
  * This class performs basic optimizations on the control flow graph after LIR generation.
  */
-public final class ControlFlowOptimizer extends LowLevelLowTierPhase {
+public final class ControlFlowOptimizer extends LIRLowTierPhase {
 
     /**
      * Performs control flow optimizations on the given LIR graph.
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Thu Feb 12 20:47:20 2015 +0100
@@ -48,7 +48,7 @@
  * Because this optimization works best when a block contains only a few moves, it has a huge impact
  * on the number of blocks that are totally empty.
  */
-public final class EdgeMoveOptimizer extends LowLevelLowTierPhase {
+public final class EdgeMoveOptimizer extends LIRLowTierPhase {
 
     @Override
     protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Thu Feb 12 20:47:20 2015 +0100
@@ -31,7 +31,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
 
-public final class NullCheckOptimizer extends LowLevelLowTierPhase {
+public final class NullCheckOptimizer extends LIRLowTierPhase {
 
     @Override
     protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Thu Feb 12 20:47:20 2015 +0100
@@ -41,7 +41,7 @@
 /**
  * Removes move instructions, where the destination value is already in place.
  */
-public final class RedundantMoveElimination extends LowLevelLowTierPhase {
+public final class RedundantMoveElimination extends LIRLowTierPhase {
 
     @Override
     protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -29,7 +29,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
 
-public final class LinearScanPhase extends LowLevelMidTierPhase {
+public final class LinearScanPhase extends LIRMidTierPhase {
 
     @Override
     protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Thu Feb 12 20:47:20 2015 +0100
@@ -42,7 +42,7 @@
  * Mark all live references for a frame state. The frame state use this information to build the OOP
  * maps.
  */
-public final class LocationMarker extends LowLevelMidTierPhase {
+public final class LocationMarker extends LIRMidTierPhase {
 
     public static class Options {
         // @formatter:off
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Thu Feb 12 20:47:20 2015 +0100
@@ -47,12 +47,12 @@
  * a constant, which is potentially scheduled into a block with high probability, with one or more
  * definitions in blocks with a lower probability.
  */
-public final class ConstantLoadOptimization extends LowLevelHighTierPhase {
+public final class ConstantLoadOptimization extends LIRHighTierPhase {
 
     public static class Options {
         // @formatter:off
         @Option(help = "Enable constant load optimization.", type = OptionType.Debug)
-        public static final OptionValue<Boolean> ConstantLoadOptimization = new OptionValue<>(true);
+        public static final OptionValue<Boolean> LIROptConstantLoadOptimization = new OptionValue<>(true);
         // @formatter:on
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRHighTier.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import com.oracle.graal.lir.constopt.*;
+import com.oracle.graal.lir.phases.LIRHighTierPhase.*;
+
+public class LIRHighTier extends LIRPhaseSuite<LIRHighTierContext> {
+    public LIRHighTier() {
+        if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue()) {
+            appendPhase(new ConstantLoadOptimization());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRHighTierPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LIRHighTierPhase extends LIRPhase<LIRHighTierPhase.LIRHighTierContext> {
+
+    public static final class LIRHighTierContext {
+        private final LIRGeneratorTool lirGen;
+
+        public LIRHighTierContext(LIRGeneratorTool lirGen) {
+            this.lirGen = lirGen;
+        }
+
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRHighTierContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.lirGen);
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRLowTier.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.phases.LIRLowTierPhase.*;
+import com.oracle.graal.options.*;
+
+public class LIRLowTier extends LIRPhaseSuite<LIRLowTierContext> {
+    public static class Options {
+        // @formatter:off
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptEdgeMoveOptimizer = new OptionValue<>(true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptControlFlowOptmizer = new OptionValue<>(true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptRedundantMoveElimination = new OptionValue<>(true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptNullCheckOptimizer = new OptionValue<>(true);
+        // @formatter:on
+    }
+
+    public LIRLowTier() {
+        if (Options.LIROptEdgeMoveOptimizer.getValue()) {
+            appendPhase(new EdgeMoveOptimizer());
+        }
+        if (Options.LIROptControlFlowOptmizer.getValue()) {
+            appendPhase(new ControlFlowOptimizer());
+        }
+        if (Options.LIROptRedundantMoveElimination.getValue()) {
+            appendPhase(new RedundantMoveElimination());
+        }
+        if (Options.LIROptNullCheckOptimizer.getValue()) {
+            appendPhase(new NullCheckOptimizer());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRLowTierPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LIRLowTierPhase extends LIRPhase<LIRLowTierPhase.LIRLowTierContext> {
+
+    public static final class LIRLowTierContext {
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRLowTierContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRMidTier.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import com.oracle.graal.lir.alloc.lsra.*;
+import com.oracle.graal.lir.phases.LIRMidTierPhase.*;
+import com.oracle.graal.lir.stackslotalloc.*;
+
+public class LIRMidTier extends LIRPhaseSuite<LIRMidTierContext> {
+    public LIRMidTier() {
+        appendPhase(new LinearScanPhase());
+
+        // build frame map
+        if (LSStackSlotAllocator.Options.LIROptLSStackSlotAllocator.getValue()) {
+            appendPhase(new LSStackSlotAllocator());
+        } else {
+            appendPhase(new SimpleStackSlotAllocator());
+        }
+        // currently we mark locations only if we do register allocation
+        appendPhase(new LocationMarker());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRMidTierPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LIRMidTierPhase extends LIRPhase<LIRMidTierPhase.LIRMidTierContext> {
+
+    public static final class LIRMidTierContext {
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRMidTierContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import java.util.*;
+import java.util.regex.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
+import com.oracle.graal.debug.internal.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
+
+/**
+ * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
+ * one global instance for each phase that is shared for all compilations.
+ */
+public abstract class LIRPhase<C> {
+
+    private static final int PHASE_DUMP_LEVEL = 2;
+
+    private CharSequence name;
+
+    /**
+     * Records time spent within {@link #apply}.
+     */
+    private final DebugTimer timer;
+
+    /**
+     * Records memory usage within {@link #apply}.
+     */
+    private final DebugMemUseTracker memUseTracker;
+
+    private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
+
+    private static boolean checkName(String name) {
+        assert name == null || NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
+        return true;
+    }
+
+    public LIRPhase() {
+        timer = Debug.timer("LIRPhaseTime_%s", getClass());
+        memUseTracker = Debug.memUseTracker("LIRPhaseMemUse_%s", getClass());
+    }
+
+    protected LIRPhase(String name) {
+        assert checkName(name);
+        this.name = name;
+        timer = Debug.timer("LIRPhaseTime_%s", getClass());
+        memUseTracker = Debug.memUseTracker("LIRPhaseMemUse_%s", getClass());
+    }
+
+    public final <B extends AbstractBlock<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
+        apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, true);
+    }
+
+    public final <B extends AbstractBlock<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context, boolean dumpLIR) {
+        try (TimerCloseable a = timer.start(); Scope s = Debug.scope(getName(), this); Closeable c = memUseTracker.start()) {
+            run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
+            if (dumpLIR && Debug.isDumpEnabled(PHASE_DUMP_LEVEL)) {
+                Debug.dump(PHASE_DUMP_LEVEL, lirGenRes.getLIR(), "After phase %s", getName());
+            }
+        } catch (Throwable e) {
+            throw Debug.handle(e);
+        }
+    }
+
+    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context);
+
+    protected CharSequence createName() {
+        String className = LIRPhase.this.getClass().getName();
+        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
+        if (s.endsWith("Phase")) {
+            s = s.substring(0, s.length() - "Phase".length());
+        }
+        return s;
+    }
+
+    public final CharSequence getName() {
+        if (name == null) {
+            name = createName();
+        }
+        return name;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhaseSuite.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+
+public abstract class LIRPhaseSuite<C> extends LIRPhase<C> {
+    private final List<LIRPhase<C>> phases;
+
+    public LIRPhaseSuite() {
+        phases = new ArrayList<>();
+    }
+
+    /**
+     * Add a new phase at the beginning of this suite.
+     */
+    public final void prependPhase(LIRPhase<C> phase) {
+        phases.add(0, phase);
+    }
+
+    /**
+     * Add a new phase at the end of this suite.
+     */
+    public final void appendPhase(LIRPhase<C> phase) {
+        phases.add(phase);
+    }
+
+    public final ListIterator<LIRPhase<C>> findPhase(Class<? extends LIRPhase<C>> phaseClass) {
+        ListIterator<LIRPhase<C>> it = phases.listIterator();
+        if (findNextPhase(it, phaseClass)) {
+            return it;
+        } else {
+            return null;
+        }
+    }
+
+    public static <C> boolean findNextPhase(ListIterator<LIRPhase<C>> it, Class<? extends LIRPhase<C>> phaseClass) {
+        while (it.hasNext()) {
+            LIRPhase<C> phase = it.next();
+            if (phaseClass.isInstance(phase)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
+        for (LIRPhase<C> phase : phases) {
+            phase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRSuites.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 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.graal.lir.phases;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.LIRHighTierPhase.LIRHighTierContext;
+import com.oracle.graal.lir.phases.LIRLowTierPhase.LIRLowTierContext;
+import com.oracle.graal.lir.phases.LIRMidTierPhase.LIRMidTierContext;
+
+public class LIRSuites {
+
+    private final LIRPhaseSuite<LIRHighTierContext> highTier;
+    private final LIRPhaseSuite<LIRMidTierContext> midTier;
+    private final LIRPhaseSuite<LIRLowTierContext> lowTier;
+
+    public LIRSuites(LIRPhaseSuite<LIRHighTierContext> highTier, LIRPhaseSuite<LIRMidTierContext> midTier, LIRPhaseSuite<LIRLowTierContext> lowTier) {
+        this.highTier = highTier;
+        this.midTier = midTier;
+        this.lowTier = lowTier;
+    }
+
+    /**
+     * {@link LIRHighTierPhase}s are executed between {@link LIR} generation and register
+     * allocation.
+     * <p>
+     * {@link LIRHighTierPhase Implementers} can create new {@link LIRGeneratorTool#newVariable
+     * variables}, {@link LIRGenerationResult#getFrameMap stack slots} and
+     * {@link LIRGenerationResult#getFrameMapBuilder virtual stack slots}.
+     */
+    public LIRPhaseSuite<LIRHighTierContext> getHighTier() {
+        return highTier;
+    }
+
+    /**
+     * {@link LIRMidTierPhase}s are responsible for register allocation and translating
+     * {@link VirtualStackSlot}s into {@link StackSlot}s.
+     * <p>
+     * After the {@link LIRMidTier} there should be no more {@link Variable}s and
+     * {@link VirtualStackSlot}s.
+     */
+    public LIRPhaseSuite<LIRMidTierContext> getMidTier() {
+        return midTier;
+    }
+
+    /**
+     * {@link LIRLowTierPhase}s are executed after register allocation and before machine code
+     * generation.
+     * <p>
+     * A {@link LIRLowTierPhase} must not introduce new {@link Variable}s, {@link VirtualStackSlot}s
+     * or {@link StackSlot}s.
+     */
+    public LIRPhaseSuite<LIRLowTierContext> getLowTier() {
+        return lowTier;
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTier.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import com.oracle.graal.lir.constopt.*;
-import com.oracle.graal.lir.phases.LowLevelHighTierPhase.*;
-
-public class LowLevelHighTier extends LowLevelPhaseSuite<LowLevelHighTierContext> {
-    public LowLevelHighTier() {
-        if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) {
-            appendPhase(new ConstantLoadOptimization());
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelHighTierPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LowLevelHighTierPhase extends LowLevelPhase<LowLevelHighTierPhase.LowLevelHighTierContext> {
-
-    public static final class LowLevelHighTierContext {
-        private final LIRGeneratorTool lirGen;
-
-        public LowLevelHighTierContext(LIRGeneratorTool lirGen) {
-            this.lirGen = lirGen;
-        }
-
-    }
-
-    @Override
-    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LowLevelHighTierContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.lirGen);
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTier.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.phases.LowLevelLowTierPhase.*;
-
-public class LowLevelLowTier extends LowLevelPhaseSuite<LowLevelLowTierContext> {
-    public LowLevelLowTier() {
-        appendPhase(new EdgeMoveOptimizer());
-        appendPhase(new ControlFlowOptimizer());
-        appendPhase(new RedundantMoveElimination());
-        appendPhase(new NullCheckOptimizer());
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelLowTierPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LowLevelLowTierPhase extends LowLevelPhase<LowLevelLowTierPhase.LowLevelLowTierContext> {
-
-    public static final class LowLevelLowTierContext {
-    }
-
-    @Override
-    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LowLevelLowTierContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTier.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import com.oracle.graal.lir.alloc.lsra.*;
-import com.oracle.graal.lir.phases.LowLevelMidTierPhase.*;
-import com.oracle.graal.lir.stackslotalloc.*;
-
-public class LowLevelMidTier extends LowLevelPhaseSuite<LowLevelMidTierContext> {
-    public LowLevelMidTier() {
-        appendPhase(new LinearScanPhase());
-
-        // build frame map
-        if (LSStackSlotAllocator.Options.LSStackSlotAllocation.getValue()) {
-            appendPhase(new LSStackSlotAllocator());
-        } else {
-            appendPhase(new SimpleStackSlotAllocator());
-        }
-        // currently we mark locations only if we do register allocation
-        appendPhase(new LocationMarker());
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelMidTierPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LowLevelMidTierPhase extends LowLevelPhase<LowLevelMidTierPhase.LowLevelMidTierContext> {
-
-    public static final class LowLevelMidTierContext {
-    }
-
-    @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LowLevelMidTierContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import java.util.*;
-import java.util.regex.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.debug.DebugMemUseTracker.Closeable;
-import com.oracle.graal.debug.internal.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.gen.*;
-
-/**
- * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
- * one global instance for each phase that is shared for all compilations.
- */
-public abstract class LowLevelPhase<C> {
-
-    private static final int PHASE_DUMP_LEVEL = 2;
-
-    private CharSequence name;
-
-    /**
-     * Records time spent within {@link #apply}.
-     */
-    private final DebugTimer timer;
-
-    /**
-     * Records memory usage within {@link #apply}.
-     */
-    private final DebugMemUseTracker memUseTracker;
-
-    private static final Pattern NAME_PATTERN = Pattern.compile("[A-Z][A-Za-z0-9]+");
-
-    private static boolean checkName(String name) {
-        assert name == null || NAME_PATTERN.matcher(name).matches() : "illegal phase name: " + name;
-        return true;
-    }
-
-    public LowLevelPhase() {
-        timer = Debug.timer("LowLevelPhaseTime_%s", getClass());
-        memUseTracker = Debug.memUseTracker("LowLevelPhaseMemUse_%s", getClass());
-    }
-
-    protected LowLevelPhase(String name) {
-        assert checkName(name);
-        this.name = name;
-        timer = Debug.timer("LowLevelPhaseTime_%s", getClass());
-        memUseTracker = Debug.memUseTracker("LowLevelPhaseMemUse_%s", getClass());
-    }
-
-    public final <B extends AbstractBlock<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
-        apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context, true);
-    }
-
-    public final <B extends AbstractBlock<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context, boolean dumpLIR) {
-        try (TimerCloseable a = timer.start(); Scope s = Debug.scope(getName(), this); Closeable c = memUseTracker.start()) {
-            run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
-            if (dumpLIR && Debug.isDumpEnabled(PHASE_DUMP_LEVEL)) {
-                Debug.dump(PHASE_DUMP_LEVEL, lirGenRes.getLIR(), "After phase %s", getName());
-            }
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context);
-
-    protected CharSequence createName() {
-        String className = LowLevelPhase.this.getClass().getName();
-        String s = className.substring(className.lastIndexOf(".") + 1); // strip the package name
-        if (s.endsWith("Phase")) {
-            s = s.substring(0, s.length() - "Phase".length());
-        }
-        return s;
-    }
-
-    public final CharSequence getName() {
-        if (name == null) {
-            name = createName();
-        }
-        return name;
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelPhaseSuite.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LowLevelPhaseSuite<C> extends LowLevelPhase<C> {
-    private final List<LowLevelPhase<C>> phases;
-
-    public LowLevelPhaseSuite() {
-        phases = new ArrayList<>();
-    }
-
-    /**
-     * Add a new phase at the beginning of this suite.
-     */
-    public final void prependPhase(LowLevelPhase<C> phase) {
-        phases.add(0, phase);
-    }
-
-    /**
-     * Add a new phase at the end of this suite.
-     */
-    public final void appendPhase(LowLevelPhase<C> phase) {
-        phases.add(phase);
-    }
-
-    public final ListIterator<LowLevelPhase<C>> findPhase(Class<? extends LowLevelPhase<C>> phaseClass) {
-        ListIterator<LowLevelPhase<C>> it = phases.listIterator();
-        if (findNextPhase(it, phaseClass)) {
-            return it;
-        } else {
-            return null;
-        }
-    }
-
-    public static <C> boolean findNextPhase(ListIterator<LowLevelPhase<C>> it, Class<? extends LowLevelPhase<C>> phaseClass) {
-        while (it.hasNext()) {
-            LowLevelPhase<C> phase = it.next();
-            if (phaseClass.isInstance(phase)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
-        for (LowLevelPhase<C> phase : phases) {
-            phase.apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, context);
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LowLevelSuites.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2015, 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.graal.lir.phases;
-
-import com.oracle.graal.lir.phases.LowLevelHighTierPhase.LowLevelHighTierContext;
-import com.oracle.graal.lir.phases.LowLevelLowTierPhase.LowLevelLowTierContext;
-import com.oracle.graal.lir.phases.LowLevelMidTierPhase.LowLevelMidTierContext;
-
-public class LowLevelSuites {
-
-    private final LowLevelPhaseSuite<LowLevelHighTierContext> highTier;
-    private final LowLevelPhaseSuite<LowLevelMidTierContext> midTier;
-    private final LowLevelPhaseSuite<LowLevelLowTierContext> lowTier;
-
-    public LowLevelSuites(LowLevelPhaseSuite<LowLevelHighTierContext> highTier, LowLevelPhaseSuite<LowLevelMidTierContext> midTier, LowLevelPhaseSuite<LowLevelLowTierContext> lowTier) {
-        this.highTier = highTier;
-        this.midTier = midTier;
-        this.lowTier = lowTier;
-    }
-
-    public LowLevelPhaseSuite<LowLevelHighTierContext> getHighTier() {
-        return highTier;
-    }
-
-    public LowLevelPhaseSuite<LowLevelMidTierContext> getMidTier() {
-        return midTier;
-    }
-
-    public LowLevelPhaseSuite<LowLevelLowTierContext> getLowTier() {
-        return lowTier;
-    }
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Thu Feb 12 20:47:20 2015 +0100
@@ -51,12 +51,12 @@
  * {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content
  * destroyed.
  */
-public final class LSStackSlotAllocator extends LowLevelMidTierPhase implements StackSlotAllocator {
+public final class LSStackSlotAllocator extends LIRMidTierPhase implements StackSlotAllocator {
 
     public static class Options {
         // @formatter:off
         @Option(help = "Use linear scan stack slot allocation.", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LSStackSlotAllocation = new OptionValue<>(true);
+        public static final OptionValue<Boolean> LIROptLSStackSlotAllocator = new OptionValue<>(true);
         // @formatter:on
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Thu Feb 12 20:47:20 2015 +0100
@@ -36,7 +36,7 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
 
-public class SimpleStackSlotAllocator extends LowLevelMidTierPhase implements StackSlotAllocator {
+public class SimpleStackSlotAllocator extends LIRMidTierPhase implements StackSlotAllocator {
 
     @Override
     protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Thu Feb 12 20:47:20 2015 +0100
@@ -233,26 +233,23 @@
         return data;
     }
 
-    public NodeBitMap nodesInLoopFrom(AbstractBeginNode point, AbstractBeginNode until) {
+    public NodeBitMap nodesInLoopBranch(AbstractBeginNode branch) {
         Collection<AbstractBeginNode> blocks = new LinkedList<>();
         Collection<LoopExitNode> exits = new LinkedList<>();
         Queue<Block> work = new LinkedList<>();
         ControlFlowGraph cfg = loopsData().controlFlowGraph();
-        work.add(cfg.blockFor(point));
-        Block untilBlock = until != null ? cfg.blockFor(until) : null;
+        work.add(cfg.blockFor(branch));
         while (!work.isEmpty()) {
             Block b = work.remove();
-            if (b == untilBlock) {
-                continue;
-            }
             if (loop().getExits().contains(b)) {
                 exits.add((LoopExitNode) b.getBeginNode());
-            } else if (loop().getBlocks().contains(b)) {
+            } else {
+                assert loop().getBlocks().contains(b);
                 blocks.add(b.getBeginNode());
                 work.addAll(b.getDominated());
             }
         }
-        return LoopFragment.computeNodes(point.graph(), blocks, exits);
+        return LoopFragment.computeNodes(branch.graph(), blocks, exits);
     }
 
     public Map<Node, InductionVariable> getInductionVariables() {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Thu Feb 12 20:47:20 2015 +0100
@@ -30,10 +30,19 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.VirtualState.VirtualClosure;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.options.*;
 
 public abstract class LoopPolicies {
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchMaxIncrease = new OptionValue<>(500);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> LoopUnswitchTrivial = new OptionValue<>(10);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Double> LoopUnswitchFrequencyBoost = new OptionValue<>(10.0);
+
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxNodes = new OptionValue<>(300);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> FullUnrollMaxIterations = new OptionValue<>(600);
+    @Option(help = "", type = OptionType.Expert) public static final OptionValue<Integer> ExactFullUnrollMaxNodes = new OptionValue<>(1200);
 
     private LoopPolicies() {
         // does not need to be instantiated
@@ -82,31 +91,57 @@
     }
 
     public static boolean shouldTryUnswitch(LoopEx loop) {
-        return loop.loopBegin().unswitches() <= LoopMaxUnswitch.getValue();
+        LoopBeginNode loopBegin = loop.loopBegin();
+        double loopFrequency = loopBegin.loopFrequency();
+        if (loopFrequency <= 1.0) {
+            return false;
+        }
+        return loopBegin.unswitches() <= LoopMaxUnswitch.getValue();
+    }
+
+    private static final class CountingClosure implements VirtualClosure {
+        int count;
+
+        public void apply(VirtualState node) {
+            count++;
+        }
+    }
+
+    private static class IsolatedInitialization {
+        static final DebugMetric UNSWITCH_SPLIT_WITH_PHIS = Debug.metric("UnswitchSplitWithPhis");
     }
 
     public static boolean shouldUnswitch(LoopEx loop, List<ControlSplitNode> controlSplits) {
-        int loopTotal = loop.size();
         int inBranchTotal = 0;
-        double maxProbability = 0;
+        int phis = 0;
         for (ControlSplitNode controlSplit : controlSplits) {
-            Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator();
-            AbstractBeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
             for (Node successor : controlSplit.successors()) {
                 AbstractBeginNode branch = (AbstractBeginNode) successor;
                 // this may count twice because of fall-through in switches
-                inBranchTotal += loop.nodesInLoopFrom(branch, postDom).count();
-                double probability = controlSplit.probability(branch);
-                if (probability > maxProbability) {
-                    maxProbability = probability;
-                }
+                inBranchTotal += loop.nodesInLoopBranch(branch).count();
+            }
+            Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator();
+            if (postDomBlock != null) {
+                IsolatedInitialization.UNSWITCH_SPLIT_WITH_PHIS.increment();
+                phis += ((MergeNode) postDomBlock.getBeginNode()).phis().count();
             }
         }
-        int netDiff = loopTotal - (inBranchTotal);
-        double uncertainty = 1 - maxProbability;
-        int maxDiff = LoopUnswitchMaxIncrease.getValue() + (int) (LoopUnswitchUncertaintyBoost.getValue() * loop.loopBegin().loopFrequency() * uncertainty);
-        Debug.log("shouldUnswitch(%s, %s) : delta=%d, max=%d, %.2f%% inside of branches", loop, controlSplits, netDiff, maxDiff, (double) (inBranchTotal) / loopTotal * 100);
-        return netDiff <= maxDiff;
+
+        CountingClosure stateNodesCount = new CountingClosure();
+        double loopFrequency = loop.loopBegin().loopFrequency();
+        int maxDiff = LoopUnswitchTrivial.getValue() + (int) (LoopUnswitchFrequencyBoost.getValue() * (loopFrequency - 1.0 + phis));
+
+        maxDiff = Math.min(maxDiff, LoopUnswitchMaxIncrease.getValue());
+        int remainingGraphSpace = MaximumDesiredSize.getValue() - loop.loopBegin().graph().getNodeCount();
+        maxDiff = Math.min(maxDiff, remainingGraphSpace);
+
+        loop.loopBegin().stateAfter().applyToVirtual(stateNodesCount);
+        int loopTotal = loop.size() - loop.loopBegin().phis().count() - stateNodesCount.count - 1;
+        int actualDiff = loopTotal - inBranchTotal;
+
+        Debug.log("shouldUnswitch(%s, %s) : delta=%d (%.2f%% inside of branches), max=%d, f=%.2f, phis=%d -> %b", loop, controlSplits, actualDiff, (double) (inBranchTotal) / loopTotal * 100, maxDiff,
+                        loopFrequency, phis, actualDiff <= maxDiff);
+        return actualDiff <= maxDiff;
     }
 
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Thu Feb 12 20:47:20 2015 +0100
@@ -37,22 +37,13 @@
 
 public abstract class LoopTransformations {
 
-    private static final int UNROLL_LIMIT = FullUnrollMaxNodes.getValue() * 2;
-
     private LoopTransformations() {
         // does not need to be instantiated
     }
 
-    public static void invert(LoopEx loop, FixedNode point) {
-        LoopFragmentInsideBefore head = loop.insideBefore(point);
-        LoopFragmentInsideBefore duplicate = head.duplicate();
-        head.disconnect();
-        head.insertBefore(loop);
-        duplicate.appendInside(loop);
-    }
-
     public static void peel(LoopEx loop) {
         loop.inside().duplicate().insertBefore(loop);
+        loop.loopBegin().setLoopFrequency(Math.max(0.0, loop.loopBegin().loopFrequency() - 1));
     }
 
     public static void fullUnroll(LoopEx loop, PhaseContext context, CanonicalizerPhase canonicalizer) {
@@ -66,7 +57,7 @@
             canonicalizer.applyIncremental(graph, context, mark);
             loopBegin.removeDeadPhis();
             loop.invalidateFragments();
-            if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) {
+            if (iterations++ > LoopPolicies.FullUnrollMaxIterations.getValue() || graph.getNodeCount() > MaximumDesiredSize.getValue() * 3) {
                 throw new BailoutException("FullUnroll : Graph seems to grow out of proportion");
             }
         }
@@ -121,27 +112,6 @@
         // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
     }
 
-    public static void unroll(LoopEx loop, int factor) {
-        assert loop.isCounted();
-        if (factor > 0) {
-            throw new UnsupportedOperationException();
-        }
-        // TODO (gd) implement counted loop
-        LoopFragmentWhole main = loop.whole();
-        LoopFragmentWhole prologue = main.duplicate();
-        prologue.insertBefore(loop);
-        // CountedLoopBeginNode counted = prologue.countedLoop();
-        // StructuredGraph graph = (StructuredGraph) counted.graph();
-        // ValueNode tripCountPrologue = counted.tripCount();
-        // ValueNode tripCountMain = counted.tripCount();
-        // graph.replaceFloating(tripCountPrologue, "tripCountPrologue % factor");
-        // graph.replaceFloating(tripCountMain, "tripCountMain - (tripCountPrologue % factor)");
-        LoopFragmentInside inside = loop.inside();
-        for (int i = 0; i < factor; i++) {
-            inside.duplicate().appendInside(loop);
-        }
-    }
-
     public static List<ControlSplitNode> findUnswitchable(LoopEx loop) {
         List<ControlSplitNode> controls = null;
         ValueNode invariantValue = null;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,6 +34,7 @@
 
     private static final DebugMetric UNSWITCHED = Debug.metric("Unswitched");
     private static final DebugMetric UNSWITCH_CANDIDATES = Debug.metric("UnswitchCandidates");
+    private static final DebugMetric UNSWITCH_EARLY_REJECTS = Debug.metric("UnswitchEarlyRejects");
 
     @Override
     protected void run(StructuredGraph graph) {
@@ -57,6 +58,8 @@
                                 break;
                             }
                         }
+                    } else {
+                        UNSWITCH_EARLY_REJECTS.increment();
                     }
                 }
             } while (unswitched);
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -31,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.
@@ -45,7 +46,7 @@
 
     @Before
     public void before() {
-        graph = new StructuredGraph();
+        graph = new StructuredGraph(AllowAssumptions.YES);
     }
 
     @Test
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/LoopPhiCanonicalizerTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/LoopPhiCanonicalizerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -27,6 +27,7 @@
 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.*;
 
@@ -56,10 +57,10 @@
 
     @Test
     public void test() {
-        StructuredGraph graph = parseEager("loopSnippet");
+        StructuredGraph graph = parseEager("loopSnippet", AllowAssumptions.YES);
         NodePredicate loopPhis = node -> node instanceof PhiNode && ((PhiNode) node).merge() instanceof LoopBeginNode;
 
-        PhaseContext context = new PhaseContext(getProviders(), null);
+        PhaseContext context = new PhaseContext(getProviders());
         Assert.assertEquals(5, graph.getNodes().filter(loopPhis).count());
         new CanonicalizerPhase(false).apply(graph, context);
         Assert.assertEquals(2, graph.getNodes().filter(loopPhis).count());
--- a/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/NegateNodeCanonicalizationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/NegateNodeCanonicalizationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -29,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.
@@ -39,7 +40,7 @@
 
     @Before
     public void before() {
-        graph = new StructuredGraph();
+        graph = new StructuredGraph(AllowAssumptions.YES);
     }
 
     @Test
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -189,6 +189,10 @@
             return;
         }
 
+        if (splitIfAtPhi(tool)) {
+            return;
+        }
+
         if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
             AbstractBeginNode intermediateBegin = falseSuccessor();
             IfNode nextIf = (IfNode) intermediateBegin.next();
@@ -602,6 +606,137 @@
     }
 
     /**
+     * Take an if that is immediately dominated by a merge with a single phi and split off any paths
+     * where the test would be statically decidable creating a new merge below the approriate side
+     * of the IfNode. Any undecidable tests will continue to use the original IfNode.
+     *
+     * @param tool
+     */
+    @SuppressWarnings("unchecked")
+    private boolean splitIfAtPhi(SimplifierTool tool) {
+        if (!(predecessor() instanceof MergeNode)) {
+            return false;
+        }
+        MergeNode merge = (MergeNode) predecessor();
+        if (merge.forwardEndCount() == 1) {
+            // Don't bother.
+            return false;
+        }
+        if (merge.usages().count() != 1 || merge.phis().count() != 1) {
+            return false;
+        }
+        if (merge.stateAfter() != null) {
+            /* We'll get the chance to simplify this after frame state assignment. */
+            return false;
+        }
+        PhiNode phi = merge.phis().first();
+        if (phi.usages().count() != 1 || condition().usages().count() != 1) {
+            /*
+             * For simplicity the below code assumes assumes the phi goes dead at the end so skip
+             * this case.
+             */
+            return false;
+        }
+
+        if (condition() instanceof Canonicalizable.Unary<?>) {
+            Canonicalizable.Unary<?> unary = (Canonicalizable.Unary<?>) condition();
+            if (unary.getValue() != phi) {
+                return false;
+            }
+        } else if (condition() instanceof Canonicalizable.Binary<?>) {
+            Canonicalizable.Binary<?> binary = (Canonicalizable.Binary<?>) condition();
+            if (binary.getX() != phi && binary.getY() != phi) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+
+        /*
+         * We could additionally filter for the case that at least some of the Phi inputs or one of
+         * the condition inputs are constants but there are cases where a non-constant is
+         * simplifiable, usually where the stamp allows the question to be answered.
+         */
+
+        /* Each successor of the if gets a new merge if needed. */
+        MergeNode trueMerge = null;
+        MergeNode falseMerge = null;
+        assert merge.stateAfter() == null;
+
+        for (AbstractEndNode end : merge.forwardEnds().snapshot()) {
+            Node value = phi.valueAt(end);
+            Node result = null;
+            if (condition() instanceof Canonicalizable.Binary<?>) {
+                Canonicalizable.Binary<Node> compare = (Canonicalizable.Binary<Node>) condition;
+                if (compare.getX() == phi) {
+                    result = compare.canonical(tool, value, compare.getY());
+                } else {
+                    result = compare.canonical(tool, compare.getX(), value);
+                }
+            } else {
+                assert condition() instanceof Canonicalizable.Unary<?>;
+                Canonicalizable.Unary<Node> compare = (Canonicalizable.Unary<Node>) condition;
+                result = compare.canonical(tool, value);
+            }
+            if (result instanceof LogicConstantNode) {
+                merge.removeEnd(end);
+                if (((LogicConstantNode) result).getValue()) {
+                    if (trueMerge == null) {
+                        trueMerge = insertMerge(trueSuccessor());
+                    }
+                    trueMerge.addForwardEnd(end);
+                } else {
+                    if (falseMerge == null) {
+                        falseMerge = insertMerge(falseSuccessor());
+                    }
+                    falseMerge.addForwardEnd(end);
+                }
+            }
+        }
+
+        cleanupMerge(tool, merge);
+        cleanupMerge(tool, trueMerge);
+        cleanupMerge(tool, falseMerge);
+
+        return true;
+    }
+
+    private void cleanupMerge(SimplifierTool tool, MergeNode merge) {
+        if (merge != null && merge.isAlive()) {
+            if (merge.forwardEndCount() == 0) {
+                GraphUtil.killCFG(merge, tool);
+            } else if (merge.forwardEndCount() == 1) {
+                graph().reduceTrivialMerge(merge);
+            }
+        }
+    }
+
+    private MergeNode insertMerge(AbstractBeginNode begin) {
+        MergeNode merge = graph().add(new MergeNode());
+        if (!begin.anchored().isEmpty()) {
+            Object before = null;
+            before = begin.anchored().snapshot();
+            begin.replaceAtUsages(InputType.Guard, merge);
+            begin.replaceAtUsages(InputType.Anchor, merge);
+            assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot();
+        }
+
+        AbstractBeginNode theBegin = begin;
+        if (begin instanceof LoopExitNode) {
+            // Insert an extra begin to make it easier.
+            theBegin = graph().add(new BeginNode());
+            begin.replaceAtPredecessor(theBegin);
+            theBegin.setNext(begin);
+        }
+        FixedNode next = theBegin.next();
+        next.replaceAtPredecessor(merge);
+        theBegin.setNext(graph().add(new EndNode()));
+        merge.addForwardEnd((EndNode) theBegin.next());
+        merge.setNext(next);
+        return merge;
+    }
+
+    /**
      * Tries to connect code that initializes a variable directly with the successors of an if
      * construct that switches on the variable. For example, the pseudo code below:
      *
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Feb 12 20:47:20 2015 +0100
@@ -25,6 +25,8 @@
 import java.util.*;
 import java.util.concurrent.atomic.*;
 
+import com.oracle.graal.api.code.*;
+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.*;
@@ -80,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;
 
@@ -94,35 +107,46 @@
     private boolean hasValueProxies = true;
 
     /**
+     * The assumptions made while constructing and transforming this graph.
+     */
+    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.
      */
-    public StructuredGraph() {
-        this(null, null);
+    public StructuredGraph(AllowAssumptions allowAssumptions) {
+        this(null, null, allowAssumptions);
     }
 
     /**
      * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start()
      * start} node.
      */
-    public StructuredGraph(String name, ResolvedJavaMethod method) {
-        this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI);
+    public StructuredGraph(String name, ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
+        this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI, allowAssumptions);
     }
 
-    public StructuredGraph(ResolvedJavaMethod method) {
-        this(null, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI);
+    public StructuredGraph(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
+        this(null, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI, allowAssumptions);
     }
 
-    public StructuredGraph(ResolvedJavaMethod method, int entryBCI) {
-        this(null, method, uniqueGraphIds.incrementAndGet(), entryBCI);
+    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) {
+    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 = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null;
     }
 
     public Stamp getReturnStamp() {
@@ -196,7 +220,17 @@
     }
 
     public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod) {
-        StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI);
+        return copy(newName, newMethod, AllowAssumptions.from(assumptions != null), isMethodRecordingEnabled());
+    }
+
+    public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod, AllowAssumptions allowAssumptions, boolean enableMethodRecording) {
+        StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI, allowAssumptions);
+        if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
+            copy.assumptions.record(assumptions);
+        }
+        if (!enableMethodRecording) {
+            copy.disableMethodRecording();
+        }
         copy.setGuardsStage(getGuardsStage());
         copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase;
         copy.hasValueProxies = hasValueProxies;
@@ -467,4 +501,37 @@
         assert !state : "cannot 'unapply' value proxy removal on graph";
         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/cfg/ControlFlowGraph.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Thu Feb 12 20:47:20 2015 +0100
@@ -275,7 +275,7 @@
                         if (sux.loop != loop) {
                             AbstractBeginNode begin = sux.getBeginNode();
                             if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
-                                Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux);
+                                Debug.log(3, "Unexpected loop exit with %s, including whole branch in the loop", sux);
                                 unexpected.add(sux);
                             }
                         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -73,10 +73,10 @@
             ResolvedJavaType exactType;
             if (objectStamp.isExactType()) {
                 exactType = objectStamp.type();
-            } else if (objectStamp.type() != null && tool.assumptions().useOptimisticAssumptions()) {
+            } else if (objectStamp.type() != null && graph().getAssumptions() != null) {
                 exactType = objectStamp.type().findUniqueConcreteSubtype();
                 if (exactType != null) {
-                    tool.assumptions().recordConcreteSubtype(objectStamp.type(), exactType);
+                    graph().getAssumptions().recordConcreteSubtype(objectStamp.type(), exactType);
                 }
             } else {
                 exactType = null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -68,10 +69,11 @@
             if (StampTool.isExactType(object)) {
                 return resolveExactMethod(tool, type);
             }
-            if (type != null && tool.assumptions().useOptimisticAssumptions()) {
+            Assumptions assumptions = graph().getAssumptions();
+            if (type != null && assumptions != null) {
                 ResolvedJavaMethod resolvedMethod = type.findUniqueConcreteMethod(method);
                 if (resolvedMethod != null && !type.isInterface() && method.getDeclaringClass().isAssignableFrom(type)) {
-                    tool.assumptions().recordConcreteMethod(method, type, resolvedMethod);
+                    assumptions.recordConcreteMethod(method, type, resolvedMethod);
                     return ConstantNode.forConstant(stamp(), resolvedMethod.getEncoding(), tool.getMetaAccess());
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,6 +26,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
 import com.oracle.graal.compiler.common.type.*;
@@ -157,11 +158,12 @@
             return synonym;
         }
 
-        if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
+        Assumptions assumptions = graph().getAssumptions();
+        if (assumptions != null) {
             ResolvedJavaType exactType = type.findUniqueConcreteSubtype();
             if (exactType != null && !exactType.equals(type)) {
                 // Propagate more precise type information to usages of the checkcast.
-                tool.assumptions().recordConcreteSubtype(type, exactType);
+                assumptions.recordConcreteSubtype(type, exactType);
                 return new CheckCastNode(exactType, object, profile, forStoreCheck);
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.spi.*;
@@ -77,12 +78,13 @@
             if (result != null) {
                 return result;
             }
-            if (tool.assumptions() != null && tool.assumptions().useOptimisticAssumptions()) {
+            Assumptions assumptions = graph().getAssumptions();
+            if (assumptions != null) {
                 ResolvedJavaType exact = stampType.findUniqueConcreteSubtype();
                 if (exact != null) {
                     result = checkInstanceOf(forValue, exact, objectStamp.nonNull(), true);
                     if (result != null) {
-                        tool.assumptions().recordConcreteSubtype(stampType, exact);
+                        assumptions.recordConcreteSubtype(stampType, exact);
                         return result;
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -94,7 +94,7 @@
         }
     }
 
-    public static ResolvedJavaMethod findSpecialCallTarget(InvokeKind invokeKind, ValueNode receiver, ResolvedJavaMethod targetMethod, Assumptions assumptions, ResolvedJavaType contextType) {
+    public static ResolvedJavaMethod findSpecialCallTarget(InvokeKind invokeKind, ValueNode receiver, ResolvedJavaMethod targetMethod, ResolvedJavaType contextType) {
         if (invokeKind.isDirect()) {
             return null;
         }
@@ -119,7 +119,8 @@
             if (resolvedMethod != null && (resolvedMethod.canBeStaticallyBound() || StampTool.isExactType(receiver) || type.isArray())) {
                 return resolvedMethod;
             }
-            if (assumptions != null && assumptions.useOptimisticAssumptions()) {
+            Assumptions assumptions = receiver.graph().getAssumptions();
+            if (assumptions != null) {
                 ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
                 if (uniqueConcreteType != null) {
                     ResolvedJavaMethod methodFromUniqueType = uniqueConcreteType.resolveConcreteMethod(targetMethod, contextType);
@@ -144,7 +145,7 @@
     public void simplify(SimplifierTool tool) {
         // attempt to devirtualize the call
         ResolvedJavaType contextType = (invoke().stateAfter() == null && invoke().stateDuring() == null) ? null : invoke().getContextType();
-        ResolvedJavaMethod specialCallTarget = findSpecialCallTarget(invokeKind, receiver(), targetMethod, tool.assumptions(), contextType);
+        ResolvedJavaMethod specialCallTarget = findSpecialCallTarget(invokeKind, receiver(), targetMethod, contextType);
         if (specialCallTarget != null) {
             this.setTargetMethod(specialCallTarget);
             setInvokeKind(InvokeKind.Special);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Thu Feb 12 20:47:20 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;
             }
@@ -80,7 +80,7 @@
         if (!(forValue.stamp() instanceof ObjectStamp)) {
             return this;
         }
-        if (!mayHaveFinalizer(forValue, tool.assumptions())) {
+        if (!mayHaveFinalizer(forValue, graph().getAssumptions())) {
             return null;
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.nodes.spi;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -43,8 +42,6 @@
 
     GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated);
 
-    Assumptions assumptions();
-
     /**
      * Gets the closest fixed node preceding the node currently being lowered.
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Thu Feb 12 20:47:20 2015 +0100
@@ -25,7 +25,6 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
@@ -83,11 +82,6 @@
     Class<? extends FixedWithNextNode> getMacroSubstitution(ResolvedJavaMethod method);
 
     /**
-     * Gets the assumptions with which replacement graphs are preprocessed.
-     */
-    Assumptions getAssumptions();
-
-    /**
      * Registers all the {@linkplain MethodSubstitution method} and {@linkplain MacroSubstitution
      * macro} substitutions defined by a given class.
      *
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -35,7 +34,7 @@
 /**
  * This tool can be used to query the current state (normal/virtualized/re-materialized) of values
  * and to describe the actions that would be taken for this state.
- * 
+ *
  * See also {@link Virtualizable}.
  */
 public interface VirtualizerTool {
@@ -52,15 +51,9 @@
     ConstantReflectionProvider getConstantReflectionProvider();
 
     /**
-     * @return the {@link Assumptions} associated with the current compilation, which can be used to
-     *         make type assumptions during virtualization.
-     */
-    Assumptions getAssumptions();
-
-    /**
      * This method should be used to query the maximum size of virtualized objects before attempting
      * virtualization.
-     * 
+     *
      * @return the maximum number of entries for virtualized objects.
      */
     int getMaximumEntryCount();
@@ -69,7 +62,7 @@
 
     /**
      * Introduces a new virtual object to the current state.
-     * 
+     *
      * @param virtualObject the new virtual object.
      * @param entryState the initial state of the virtual object's fields.
      * @param locks the initial locking depths.
@@ -79,7 +72,7 @@
     /**
      * Queries the current state of the given value: if it is virtualized (thread-local and the
      * compiler knows all entries) or not.
-     * 
+     *
      * @param value the value whose state should be queried.
      * @return the {@link State} representing the value if it has been virtualized at some point,
      *         null otherwise.
@@ -88,7 +81,7 @@
 
     /**
      * Sets the entry (field or array element) with the given index in the virtualized object.
-     * 
+     *
      * @param state the state.
      * @param index the index to be set.
      * @param value the new value for the given index.
@@ -102,7 +95,7 @@
      * Replacements via {@link #replaceWithValue(ValueNode)} are not immediately committed. This
      * method can be used to determine if a value was replaced by another one (e.g., a load field by
      * the loaded value).
-     * 
+     *
      * @param original the original input value.
      * @return the replacement value, or the original value if there is no replacement.
      */
@@ -112,14 +105,14 @@
 
     /**
      * Deletes the current node and replaces it with the given virtualized object.
-     * 
+     *
      * @param virtual the virtualized object that should replace the current node.
      */
     void replaceWithVirtual(VirtualObjectNode virtual);
 
     /**
      * Deletes the current node and replaces it with the given value.
-     * 
+     *
      * @param replacement the value that should replace the current node.
      */
     void replaceWithValue(ValueNode replacement);
@@ -131,7 +124,7 @@
 
     /**
      * Replaces an input of the current node.
-     * 
+     *
      * @param oldInput the old input value.
      * @param replacement the new input value.
      */
@@ -140,7 +133,7 @@
     /**
      * Adds the given node to the graph.This action will only be performed when, and if, the changes
      * are committed.
-     * 
+     *
      * @param node the node to add.
      */
     void addNode(ValueNode node);
@@ -148,7 +141,7 @@
     /**
      * This method performs either {@link #replaceWithValue(ValueNode)} or
      * {@link #replaceWithVirtual(VirtualObjectNode)}, depending on the given value.
-     * 
+     *
      * @param value the replacement value
      */
     void replaceWith(ValueNode value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
@@ -473,22 +472,16 @@
     }
 
     private static final class DefaultSimplifierTool implements SimplifierTool {
-        private final Assumptions assumptions;
         private final MetaAccessProvider metaAccess;
         private final ConstantReflectionProvider constantReflection;
         private final boolean canonicalizeReads;
 
-        public DefaultSimplifierTool(Assumptions assumptions, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean canonicalizeReads) {
-            this.assumptions = assumptions;
+        public DefaultSimplifierTool(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean canonicalizeReads) {
             this.metaAccess = metaAccess;
             this.constantReflection = constantReflection;
             this.canonicalizeReads = canonicalizeReads;
         }
 
-        public Assumptions assumptions() {
-            return assumptions;
-        }
-
         public MetaAccessProvider getMetaAccess() {
             return metaAccess;
         }
@@ -517,7 +510,7 @@
         }
     }
 
-    public static SimplifierTool getDefaultSimplifier(Assumptions assumptions, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean canonicalizeReads) {
-        return new DefaultSimplifierTool(assumptions, metaAccess, constantReflection, canonicalizeReads);
+    public static SimplifierTool getDefaultSimplifier(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean canonicalizeReads) {
+        return new DefaultSimplifierTool(metaAccess, constantReflection, canonicalizeReads);
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,12 +22,13 @@
  */
 package com.oracle.graal.phases.common;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.*;
+import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.Graph.NodeEventListener;
+import com.oracle.graal.graph.Graph.NodeEventScope;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -394,15 +395,6 @@
                 GraphUtil.killCFG(branch, this);
             }
 
-            /**
-             * @return an object that can be used for recording assumptions or {@code null} if
-             *         assumptions are not allowed in the current context.
-             */
-            @Override
-            public Assumptions assumptions() {
-                return context.getAssumptions();
-            }
-
             @Override
             public MetaAccessProvider getMetaAccess() {
                 return context.getMetaAccess();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -49,7 +49,7 @@
  *
  */
 public class ConvertDeoptimizeToGuardPhase extends Phase {
-    private SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false);
+    private SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, false);
 
     private static AbstractBeginNode findBeginNode(FixedNode startNode) {
         return GraphUtil.predecessorIterable(startNode).filter(AbstractBeginNode.class).first();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,7 +26,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.Graph.Mark;
@@ -120,11 +119,6 @@
             return createGuard(before, condition, deoptReason, action, false);
         }
 
-        @Override
-        public Assumptions assumptions() {
-            return context.getAssumptions();
-        }
-
         public StampProvider getStampProvider() {
             return context.getStampProvider();
         }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -27,9 +27,8 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.inlining.policy.GreedyInliningPolicy;
-import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
-import com.oracle.graal.phases.common.inlining.walker.InliningData;
+import com.oracle.graal.phases.common.inlining.policy.*;
+import com.oracle.graal.phases.common.inlining.walker.*;
 import com.oracle.graal.phases.tiers.*;
 
 public class InliningPhase extends AbstractInliningPhase {
@@ -93,5 +92,4 @@
         assert data.inliningDepth() == 0;
         assert data.graphCount() == 0;
     }
-
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Thu Feb 12 20:47:20 2015 +0100
@@ -114,7 +114,15 @@
 
     public static void logNotInlinedMethod(Invoke invoke, String msg) {
         if (shouldLogInliningDecision()) {
-            String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName());
+            String methodString = invoke.toString();
+            if (invoke.callTarget() == null) {
+                methodString += " callTarget=null";
+            } else {
+                String targetName = invoke.callTarget().targetName();
+                if (!methodString.endsWith(targetName)) {
+                    methodString += " " + targetName;
+                }
+            }
             logInliningDecision(methodString, false, msg, new Object[0]);
         }
     }
@@ -355,6 +363,21 @@
         invokeNode.replaceAtUsages(null);
         GraphUtil.killCFG(invokeNode);
 
+        // Copy assumptions from inlinee to caller
+        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;
+        }
+
+        // Copy method dependencies from inlinee to caller
+        if (inlineGraph.isMethodRecordingEnabled() && graph.isMethodRecordingEnabled()) {
+            graph.getMethods().addAll(inlineGraph.getMethods());
+        }
+
         return duplicates;
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,16 +24,13 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.Assumptions;
-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 {
 
@@ -53,7 +50,7 @@
         return invoke;
     }
 
-    protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
+    protected static Collection<Node> inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, boolean receiverNullCheck) {
         List<Node> canonicalizeNodes = new ArrayList<>();
         if (inlineable instanceof InlineableGraph) {
             StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
@@ -68,7 +65,10 @@
         }
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
-        assumptions.recordMethodContents(concrete);
+        StructuredGraph graph = invoke.asNode().graph();
+        if (graph.isMethodRecordingEnabled()) {
+            graph.getMethods().add(concrete);
+        }
         return canonicalizeNodes;
     }
 
@@ -83,9 +83,9 @@
         }
     }
 
-    public final void populateInlinableElements(HighTierContext context, Assumptions calleeAssumptions, CanonicalizerPhase canonicalizer) {
+    public final void populateInlinableElements(HighTierContext context, StructuredGraph caller, CanonicalizerPhase canonicalizer) {
         for (int i = 0; i < numberOfMethods(); i++) {
-            Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context.replaceAssumptions(calleeAssumptions), canonicalizer);
+            Inlineable elem = Inlineable.getInlineableElement(methodAt(i), invoke, context, canonicalizer);
             setInlinableElement(i, elem);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.code.Assumptions.Assumption;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
@@ -47,14 +46,14 @@
     }
 
     @Override
-    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
-        assumptions.record(takenAssumption);
-        return super.inline(providers, assumptions);
+    public Collection<Node> inline(Providers providers) {
+        invoke.asNode().graph().getAssumptions().record(takenAssumption);
+        return super.inline(providers);
     }
 
     @Override
-    public void tryToDevirtualizeInvoke(Providers providers, Assumptions assumptions) {
-        assumptions.record(takenAssumption);
+    public void tryToDevirtualizeInvoke(Providers providers) {
+        invoke.asNode().graph().getAssumptions().record(takenAssumption);
         InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -52,12 +51,12 @@
     }
 
     @Override
-    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
-        return inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
+    public Collection<Node> inline(Providers providers) {
+        return inline(invoke, concrete, inlineableElement, !suppressNullCheck);
     }
 
     @Override
-    public void tryToDevirtualizeInvoke(Providers providers, Assumptions assumptions) {
+    public void tryToDevirtualizeInvoke(Providers providers) {
         // nothing todo, can already be bound statically
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -74,16 +73,16 @@
      *
      * @return a collection of nodes that need to be canonicalized after the inlining
      */
-    Collection<Node> inline(Providers providers, Assumptions assumptions);
+    Collection<Node> inline(Providers providers);
 
     /**
      * Try to make the call static bindable to avoid interface and virtual method calls.
      */
-    void tryToDevirtualizeInvoke(Providers providers, Assumptions assumptions);
+    void tryToDevirtualizeInvoke(Providers providers);
 
     boolean shouldInline();
 
-    void populateInlinableElements(HighTierContext context, Assumptions calleeAssumptions, CanonicalizerPhase canonicalizer);
+    void populateInlinableElements(HighTierContext context, StructuredGraph caller, CanonicalizerPhase canonicalizer);
 
     int determineNodeCount();
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,7 +26,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
 import com.oracle.graal.compiler.common.calc.*;
@@ -142,11 +141,11 @@
     }
 
     @Override
-    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+    public Collection<Node> inline(Providers providers) {
         if (hasSingleMethod()) {
-            return inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions, providers.getStampProvider());
+            return inlineSingleMethod(graph(), providers.getMetaAccess(), providers.getStampProvider());
         } else {
-            return inlineMultipleMethods(graph(), providers, assumptions);
+            return inlineMultipleMethods(graph(), providers);
         }
     }
 
@@ -167,7 +166,7 @@
         return notRecordedTypeProbability > 0;
     }
 
-    private Collection<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
+    private Collection<Node> inlineMultipleMethods(StructuredGraph graph, Providers providers) {
         int numberOfMethods = concretes.size();
         FixedNode continuation = invoke.next();
 
@@ -276,7 +275,7 @@
             if (opportunities > 0) {
                 metricInliningTailDuplication.increment();
                 Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+                PhaseContext phaseContext = new PhaseContext(providers);
                 CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
                 TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
             }
@@ -286,7 +285,7 @@
         // do the actual inlining for every invoke
         for (int i = 0; i < numberOfMethods; i++) {
             Invoke invokeForInlining = (Invoke) successors[i].next();
-            canonicalizeNodes.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false));
+            canonicalizeNodes.addAll(inline(invokeForInlining, methodAt(i), inlineableElementAt(i), false));
         }
         if (returnValuePhi != null) {
             canonicalizeNodes.add(returnValuePhi);
@@ -327,7 +326,7 @@
         return result;
     }
 
-    private Collection<Node> inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions, StampProvider stampProvider) {
+    private Collection<Node> inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, StampProvider stampProvider) {
         assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
         AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
@@ -338,7 +337,7 @@
 
         calleeEntryNode.setNext(invoke.asNode());
 
-        return inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
+        return inline(invoke, methodAt(0), inlineableElementAt(0), false);
     }
 
     private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess, StampProvider stampProvider) {
@@ -511,7 +510,7 @@
     }
 
     @Override
-    public void tryToDevirtualizeInvoke(Providers providers, Assumptions assumptions) {
+    public void tryToDevirtualizeInvoke(Providers providers) {
         if (hasSingleMethod()) {
             devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), providers.getMetaAccess(), providers.getStampProvider());
         } else {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
@@ -90,13 +89,13 @@
     }
 
     @Override
-    public Collection<Node> inline(Providers providers, Assumptions assumptions) {
+    public Collection<Node> inline(Providers providers) {
         createGuard(graph(), providers);
-        return inline(invoke, concrete, inlineableElement, assumptions, false);
+        return inline(invoke, concrete, inlineableElement, false);
     }
 
     @Override
-    public void tryToDevirtualizeInvoke(Providers providers, Assumptions assumptions) {
+    public void tryToDevirtualizeInvoke(Providers providers) {
         createGuard(graph(), providers);
         InliningUtil.replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Thu Feb 12 20:47:20 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.*;
@@ -58,7 +59,7 @@
     private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache();
 
     public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer) {
-        StructuredGraph original = getOriginalGraph(method, context, canonicalizer);
+        StructuredGraph original = getOriginalGraph(method, context, canonicalizer, invoke.asNode().graph());
         // TODO copying the graph is only necessary if it is modified or if it contains any invokes
         this.graph = original.copy();
         specializeGraphToArguments(invoke, context, canonicalizer);
@@ -69,7 +70,7 @@
      * The graph thus obtained is returned, ie the caller is responsible for cloning before
      * modification.
      */
-    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer) {
+    private static StructuredGraph getOriginalGraph(final ResolvedJavaMethod method, final HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
         StructuredGraph result = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
         if (result != null) {
             return result;
@@ -78,7 +79,7 @@
         if (result != null) {
             return result;
         }
-        return parseBytecodes(method, context, canonicalizer);
+        return parseBytecodes(method, context, canonicalizer, caller);
     }
 
     /**
@@ -184,6 +185,8 @@
         if (context.getGraphCache() != null) {
             StructuredGraph cachedGraph = context.getGraphCache().get(method);
             if (cachedGraph != null) {
+                // TODO: check that cachedGraph.getAssumptions() are still valid
+                // instead of waiting for code installation to do it.
                 return cachedGraph;
             }
         }
@@ -195,9 +198,16 @@
      * Provided profiling info is mature, the resulting graph is cached. The caller is responsible
      * for cloning before modification.</p>
      */
-    private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer) {
-        StructuredGraph newGraph = new StructuredGraph(method);
+    private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer, StructuredGraph caller) {
+        StructuredGraph newGraph = new StructuredGraph(method, AllowAssumptions.from(caller.getAssumptions() != null));
         try (Debug.Scope s = Debug.scope("InlineGraph", newGraph)) {
+            if (!caller.isMethodRecordingEnabled()) {
+                // Don't record method dependencies in the inlinee if
+                // the caller doesn't want them. This decision is
+                // preserved in the graph cache (if used) which is
+                // ok since the graph cache is compilation local.
+                newGraph.disableMethodRecording();
+            }
             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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Thu Feb 12 20:47:20 2015 +0100
@@ -100,8 +100,7 @@
         this.inliningPolicy = inliningPolicy;
         this.maxGraphs = 1;
 
-        Assumptions rootAssumptions = context.getAssumptions();
-        invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0, null));
+        invocationQueue.push(new MethodInvocation(null, 1.0, 1.0, null));
         graphQueue.push(new CallsiteHolderExplorable(rootGraph, 1.0, 1.0, null));
     }
 
@@ -145,7 +144,7 @@
      * @param invoke the invoke that should be inlined
      * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
      */
-    private InlineInfo getInlineInfo(Invoke invoke, Assumptions assumptions) {
+    private InlineInfo getInlineInfo(Invoke invoke) {
         final String failureMessage = InliningUtil.checkInvokeConditions(invoke);
         if (failureMessage != null) {
             InliningUtil.logNotInlinedMethod(invoke, failureMessage);
@@ -194,7 +193,7 @@
             }
         }
 
-        if (assumptions.useOptimisticAssumptions()) {
+        if (callTarget.graph().getAssumptions() != null) {
             ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
             if (uniqueSubtype != null) {
                 ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveConcreteMethod(targetMethod, contextType);
@@ -354,16 +353,15 @@
         return null;
     }
 
-    private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation, Assumptions callerAssumptions) {
+    private void doInline(CallsiteHolderExplorable callerCallsiteHolder, MethodInvocation calleeInvocation) {
         StructuredGraph callerGraph = callerCallsiteHolder.graph();
         InlineInfo calleeInfo = calleeInvocation.callee();
         try {
             try (Debug.Scope scope = Debug.scope("doInline", callerGraph)) {
                 Set<Node> canonicalizedNodes = Node.newSet();
                 calleeInfo.invoke().asNode().usages().snapshotTo(canonicalizedNodes);
-                Collection<Node> parameterUsages = calleeInfo.inline(new Providers(context), callerAssumptions);
+                Collection<Node> parameterUsages = calleeInfo.inline(new Providers(context));
                 canonicalizedNodes.addAll(parameterUsages);
-                callerAssumptions.record(calleeInvocation.assumptions());
                 metricInliningRuns.increment();
                 Debug.dump(callerGraph, "after %s", calleeInfo);
 
@@ -409,20 +407,19 @@
      *
      * @return true iff inlining was actually performed
      */
-    private boolean tryToInline(MethodInvocation calleeInvocation, MethodInvocation parentInvocation, int inliningDepth) {
+    private boolean tryToInline(MethodInvocation calleeInvocation, int inliningDepth) {
         CallsiteHolderExplorable callerCallsiteHolder = (CallsiteHolderExplorable) currentGraph();
         InlineInfo calleeInfo = calleeInvocation.callee();
         assert callerCallsiteHolder.containsInvoke(calleeInfo.invoke());
-        Assumptions callerAssumptions = parentInvocation.assumptions();
         metricInliningConsidered.increment();
 
         if (inliningPolicy.isWorthInlining(context.getReplacements(), calleeInvocation, inliningDepth, true)) {
-            doInline(callerCallsiteHolder, calleeInvocation, callerAssumptions);
+            doInline(callerCallsiteHolder, calleeInvocation);
             return true;
         }
 
         if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
-            calleeInfo.tryToDevirtualizeInvoke(new Providers(context), callerAssumptions);
+            calleeInfo.tryToDevirtualizeInvoke(new Providers(context));
         }
 
         return false;
@@ -450,22 +447,19 @@
      * <p>
      * The {@link InlineInfo} used to get things rolling is kept around in the
      * {@link MethodInvocation}, it will be needed in case of inlining, see
-     * {@link InlineInfo#inline(Providers, Assumptions)}
+     * {@link InlineInfo#inline(Providers)}
      * </p>
      */
     private void processNextInvoke() {
         CallsiteHolderExplorable callsiteHolder = (CallsiteHolderExplorable) currentGraph();
         Invoke invoke = callsiteHolder.popInvoke();
-        MethodInvocation callerInvocation = currentInvocation();
-        Assumptions parentAssumptions = callerInvocation.assumptions();
-        InlineInfo info = getInlineInfo(invoke, parentAssumptions);
+        InlineInfo info = getInlineInfo(invoke);
 
         if (info != null) {
-            Assumptions calleeAssumptions = new Assumptions(parentAssumptions.useOptimisticAssumptions());
-            info.populateInlinableElements(context, calleeAssumptions, canonicalizer);
+            info.populateInlinableElements(context, currentGraph().graph(), canonicalizer);
             double invokeProbability = callsiteHolder.invokeProbability(invoke);
             double invokeRelevance = callsiteHolder.invokeRelevance(invoke);
-            MethodInvocation methodInvocation = new MethodInvocation(info, calleeAssumptions, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
+            MethodInvocation methodInvocation = new MethodInvocation(info, invokeProbability, invokeRelevance, freshlyInstantiatedArguments(invoke, callsiteHolder.getFixedParams()));
             pushInvocationAndGraphs(methodInvocation);
         }
     }
@@ -640,12 +634,12 @@
      * {@link #processNextInvoke() delve} into one of the callsites hosted in the current graph,
      * such callsite is explored next by {@link #moveForward()}</li>
      * <li>
-     * {@link #tryToInline(MethodInvocation, MethodInvocation, int) try to inline}: move past the
-     * current graph (remove it from the topmost element).
+     * {@link #tryToInline(MethodInvocation, int) try to inline}: move past the current graph
+     * (remove it from the topmost element).
      * <ul>
      * <li>
-     * If that was the last one then {@link #tryToInline(MethodInvocation, MethodInvocation, int)
-     * try to inline} the callsite under consideration (ie, the "current invocation").</li>
+     * If that was the last one then {@link #tryToInline(MethodInvocation, int) try to inline} the
+     * callsite under consideration (ie, the "current invocation").</li>
      * <li>
      * Whether inlining occurs or not, that callsite is removed from the top of {@link InliningData}
      * .</li>
@@ -703,9 +697,8 @@
              * "all concrete methods that come into question already had the callees they contain analyzed for inlining"
              */
             popInvocation();
-            final MethodInvocation parentInvoke = currentInvocation();
             try (Debug.Scope s = Debug.scope("Inlining", inliningContext())) {
-                return tryToInline(currentInvocation, parentInvoke, inliningDepth() + 1);
+                return tryToInline(currentInvocation, inliningDepth() + 1);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,16 +22,13 @@
  */
 package com.oracle.graal.phases.common.inlining.walker;
 
-import com.oracle.graal.api.code.Assumptions;
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.nodes.CallTargetNode;
-import com.oracle.graal.nodes.java.MethodCallTargetNode;
-import com.oracle.graal.phases.common.inlining.info.InlineInfo;
-import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
+import java.util.*;
 
-import java.util.BitSet;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.common.inlining.info.*;
+import com.oracle.graal.phases.common.inlining.info.elem.*;
 
 /**
  * <p>
@@ -47,7 +44,6 @@
 public class MethodInvocation {
 
     private final InlineInfo callee;
-    private final Assumptions assumptions;
     private final double probability;
     private final double relevance;
 
@@ -79,9 +75,8 @@
 
     private final int sizeFreshArgs;
 
-    public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
+    public MethodInvocation(InlineInfo info, double probability, double relevance, BitSet freshlyInstantiatedArguments) {
         this.callee = info;
-        this.assumptions = assumptions;
         this.probability = probability;
         this.relevance = relevance;
         this.freshlyInstantiatedArguments = freshlyInstantiatedArguments;
@@ -106,10 +101,6 @@
         return callee;
     }
 
-    public Assumptions assumptions() {
-        return assumptions;
-    }
-
     public double probability() {
         return probability;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,9 +24,9 @@
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.lir.phases.LowLevelHighTierPhase.*;
-import com.oracle.graal.lir.phases.LowLevelLowTierPhase.*;
-import com.oracle.graal.lir.phases.LowLevelMidTierPhase.*;
+import com.oracle.graal.lir.phases.LIRHighTierPhase.*;
+import com.oracle.graal.lir.phases.LIRLowTierPhase.*;
+import com.oracle.graal.lir.phases.LIRMidTierPhase.*;
 import com.oracle.graal.phases.*;
 
 public interface CompilerConfiguration extends Service {
@@ -37,9 +37,9 @@
 
     PhaseSuite<LowTierContext> createLowTier();
 
-    LowLevelPhaseSuite<LowLevelHighTierContext> createLowLevelHighTier();
+    LIRPhaseSuite<LIRHighTierContext> createLIRHighTier();
 
-    LowLevelPhaseSuite<LowLevelMidTierContext> createLowLevelMidTier();
+    LIRPhaseSuite<LIRMidTierContext> createLIRMidTier();
 
-    LowLevelPhaseSuite<LowLevelLowTierContext> createLowLevelLowTier();
+    LIRPhaseSuite<LIRLowTierContext> createLIRLowTier();
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
@@ -37,9 +36,8 @@
     private final Map<ResolvedJavaMethod, StructuredGraph> cache;
     private final OptimisticOptimizations optimisticOpts;
 
-    public HighTierContext(Providers providers, Assumptions assumptions, Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite,
-                    OptimisticOptimizations optimisticOpts) {
-        super(providers, assumptions);
+    public HighTierContext(Providers providers, Map<ResolvedJavaMethod, StructuredGraph> cache, PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts) {
+        super(providers);
         this.cache = cache;
         this.graphBuilderSuite = graphBuilderSuite;
         this.optimisticOpts = optimisticOpts;
@@ -56,8 +54,4 @@
     public OptimisticOptimizations getOptimisticOptimizations() {
         return optimisticOpts;
     }
-
-    public HighTierContext replaceAssumptions(Assumptions newAssumptions) {
-        return new HighTierContext(new Providers(this), newAssumptions, cache, graphBuilderSuite, optimisticOpts);
-    }
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java	Thu Feb 12 20:47:20 2015 +0100
@@ -29,8 +29,8 @@
 
     private final TargetDescription target;
 
-    public LowTierContext(Providers copyFrom, Assumptions assumptions, TargetDescription target) {
-        super(copyFrom, assumptions);
+    public LowTierContext(Providers copyFrom, TargetDescription target) {
+        super(copyFrom);
         this.target = target;
     }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,8 +34,8 @@
     private final ProfilingInfo profilingInfo;
     private final SpeculationLog log;
 
-    public MidTierContext(Providers copyFrom, Assumptions assumptions, TargetDescription target, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, SpeculationLog log) {
-        super(copyFrom, assumptions);
+    public MidTierContext(Providers copyFrom, TargetDescription target, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, SpeculationLog log) {
+        super(copyFrom);
         this.target = target;
         this.optimisticOpts = optimisticOpts;
         this.profilingInfo = profilingInfo;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,7 +22,6 @@
  */
 package com.oracle.graal.phases.tiers;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.util.*;
@@ -33,21 +32,18 @@
     private final ConstantReflectionProvider constantReflection;
     private final LoweringProvider lowerer;
     private final Replacements replacements;
-    private final Assumptions assumptions;
     private final StampProvider stampProvider;
 
-    public PhaseContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, LoweringProvider lowerer, Replacements replacements, Assumptions assumptions,
-                    StampProvider stampProvider) {
+    public PhaseContext(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, LoweringProvider lowerer, Replacements replacements, StampProvider stampProvider) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
         this.lowerer = lowerer;
         this.replacements = replacements;
-        this.assumptions = assumptions;
         this.stampProvider = stampProvider;
     }
 
-    public PhaseContext(Providers providers, Assumptions assumptions) {
-        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getLowerer(), providers.getReplacements(), assumptions, providers.getStampProvider());
+    public PhaseContext(Providers providers) {
+        this(providers.getMetaAccess(), providers.getConstantReflection(), providers.getLowerer(), providers.getReplacements(), providers.getStampProvider());
     }
 
     public MetaAccessProvider getMetaAccess() {
@@ -66,10 +62,6 @@
         return replacements;
     }
 
-    public Assumptions getAssumptions() {
-        return assumptions;
-    }
-
     public StampProvider getStampProvider() {
         return stampProvider;
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Thu Feb 12 20:47:20 2015 +0100
@@ -130,21 +130,21 @@
         return new Suites(config);
     }
 
-    public static LowLevelSuites createDefaultLowLevelSuites() {
+    public static LIRSuites createDefaultLIRSuites() {
         String selected = CompilerConfiguration.getValue();
         if (selected.equals("")) {
-            return new LowLevelSuites(defaultConfiguration.createLowLevelHighTier(), defaultConfiguration.createLowLevelMidTier(), defaultConfiguration.createLowLevelLowTier());
+            return new LIRSuites(defaultConfiguration.createLIRHighTier(), defaultConfiguration.createLIRMidTier(), defaultConfiguration.createLIRLowTier());
         } else {
-            return createLowLevelSuites(selected);
+            return createLIRSuites(selected);
         }
     }
 
-    public static LowLevelSuites createLowLevelSuites(String name) {
+    public static LIRSuites createLIRSuites(String name) {
         CompilerConfiguration config = configurations.get(name);
         if (config == null) {
             throw new GraalInternalError("unknown compiler configuration: " + name);
         }
-        return new LowLevelSuites(config.createLowLevelHighTier(), config.createLowLevelMidTier(), config.createLowLevelLowTier());
+        return new LIRSuites(config.createLIRHighTier(), config.createLIRMidTier(), config.createLIRLowTier());
     }
 
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java	Thu Feb 12 20:47:20 2015 +0100
@@ -46,12 +46,12 @@
     /**
      * Get the default phase suites of this compiler.
      */
-    LowLevelSuites getDefaultLowLevelSuites();
+    LIRSuites getDefaultLIRSuites();
 
     /**
      * Create a new set of low-level phase suites. Initially, the suites are the same as the
-     * {@link #getDefaultLowLevelSuites default} suites.
+     * {@link #getDefaultLIRSuites default} suites.
      */
-    LowLevelSuites createLowLevelSuites();
+    LIRSuites createLIRSuites();
 
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,8 +26,8 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -330,11 +330,10 @@
 
     @Test
     public void testCanonicalLength() {
-        StructuredGraph graph = parseEager("testCanonicalLengthSnippet");
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
         Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asJavaConstant().asLong() == 0);
     }
@@ -347,11 +346,10 @@
 
     @Test
     public void testCanonicalEqual() {
-        StructuredGraph graph = parseEager("testCanonicalEqualSnippet");
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
         Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asJavaConstant().asLong() == 1);
     }
@@ -362,13 +360,12 @@
 
     @Test
     public void testVirtualEqual() {
-        StructuredGraph graph = parseEager("testVirtualEqualSnippet");
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
         Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asJavaConstant().asLong() == 1);
     }
@@ -381,13 +378,12 @@
 
     @Test
     public void testVirtualNotEqual() {
-        StructuredGraph graph = parseEager("testVirtualNotEqualSnippet");
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), assumptions));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
         Assert.assertTrue(graph.getNodes(ReturnNode.class).first().result().asJavaConstant().asLong() == 0);
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,11 +24,11 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -247,8 +247,8 @@
      * @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);
-        HighTierContext context = new HighTierContext(getProviders(), new Assumptions(false), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
+        StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase(true);
         canonicalizer.apply(graph, context);
         new InliningPhase(canonicalizer).apply(graph, context);
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Thu Feb 12 20:47:20 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) {
-        StructuredGraph graph = super.parseEager(m);
+    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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,13 +26,13 @@
 
 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.graph.*;
 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.*;
@@ -54,7 +54,7 @@
 
     }
 
-    StructuredGraph graph = new StructuredGraph();
+    StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO);
     TestNode node;
     ConstantNode i1;
     ConstantNode i2;
@@ -113,9 +113,8 @@
         }
 
         ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(method);
-        StructuredGraph g = parseProfiled(javaMethod);
-        Assumptions assumptions = new Assumptions(false);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        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);
         Assert.assertTrue(g.getNodes().filter(CheckCastNode.class).isEmpty());
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,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.*;
@@ -48,9 +49,8 @@
 
     protected StructuredGraph test(final String snippet) {
         try (Scope s = Debug.scope("MethodSubstitutionTest", getResolvedJavaMethod(snippet))) {
-            StructuredGraph graph = parseEager(snippet);
-            Assumptions assumptions = new Assumptions(true);
-            HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+            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);
             Debug.dump(graph, "Graph");
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,6 +28,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.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.replacements.*;
@@ -45,55 +46,55 @@
     private final ReplacementsImpl installer;
 
     public ObjectAccessTest() {
-        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), new Assumptions(false), getTarget());
+        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m) {
+    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"), 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"), 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"), 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"), 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"), 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"), 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -28,6 +28,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.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.phases.*;
@@ -51,55 +52,55 @@
 
     public PointerTest() {
         target = getCodeCache().getTarget();
-        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), new Assumptions(false), getTarget());
+        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m) {
+    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"), 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"), 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"), 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"), 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"), 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"), true, LocationIdentity.ANY_LOCATION);
+            assertWrite(parseEager("write" + kind.name() + "3", AllowAssumptions.YES), true, LocationIdentity.ANY_LOCATION);
         }
     }
 
@@ -399,10 +400,9 @@
     }
 
     private void assertNumWordCasts(String snippetName, int expectedWordCasts) {
-        Assumptions assumptions = new Assumptions(true);
-        HighTierContext context = new HighTierContext(getProviders(), assumptions, null, null, OptimisticOptimizations.ALL);
+        HighTierContext context = new HighTierContext(getProviders(), null, null, OptimisticOptimizations.ALL);
 
-        StructuredGraph graph = parseEager(snippetName);
+        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 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,10 +24,10 @@
 
 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.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
@@ -41,13 +41,13 @@
     private final ReplacementsImpl installer;
 
     public WordTest() {
-        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), new Assumptions(false), getTarget());
+        installer = new ReplacementsImpl(getProviders(), getSnippetReflection(), getTarget());
     }
 
     private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
 
     @Override
-    protected StructuredGraph parseEager(ResolvedJavaMethod m) {
+    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/GraphKit.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Thu Feb 12 20:47:20 2015 +0100
@@ -206,7 +206,7 @@
      */
     public void inline(InvokeNode invoke, SnippetReflectionProvider snippetReflection) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl repl = new ReplacementsImpl(providers, snippetReflection, new Assumptions(false), providers.getCodeCache().getTarget());
+        ReplacementsImpl repl = new ReplacementsImpl(providers, snippetReflection, providers.getCodeCache().getTarget());
         StructuredGraph calleeGraph = repl.makeGraph(method, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
         InliningUtil.inline(invoke, calleeGraph, false, null);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -47,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.*;
@@ -63,7 +64,6 @@
     public final Providers providers;
     public final SnippetReflectionProvider snippetReflection;
     public final TargetDescription target;
-    public final Assumptions assumptions;
 
     /**
      * The preprocessed replacement graphs.
@@ -219,13 +219,12 @@
     // it is stable across VM executions (in support of replay compilation).
     private final Map<String, SnippetTemplateCache> snippetTemplateCache;
 
-    public ReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, Assumptions assumptions, TargetDescription target) {
+    public ReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, TargetDescription target) {
         this.providers = providers.copyWith(this);
         this.classReplacements = CollectionsFactory.newMap();
         this.internalNameToSubstitutionClasses = CollectionsFactory.newMap();
         this.snippetReflection = snippetReflection;
         this.target = target;
-        this.assumptions = assumptions;
         this.graphs = new ConcurrentHashMap<>();
         this.snippetTemplateCache = CollectionsFactory.newMap();
     }
@@ -287,7 +286,7 @@
         // Do deferred intrinsification of node intrinsics
 
         createNodeIntrinsificationPhase().apply(specializedSnippet);
-        new CanonicalizerPhase(true).apply(specializedSnippet, new PhaseContext(providers, assumptions));
+        new CanonicalizerPhase(true).apply(specializedSnippet, new PhaseContext(providers));
         NodeIntrinsificationVerificationPhase.verify(specializedSnippet);
     }
 
@@ -319,10 +318,6 @@
         return cr == null ? null : cr.macroSubstitutions.get(method);
     }
 
-    public Assumptions getAssumptions() {
-        return assumptions;
-    }
-
     private SubstitutionGuard getGuard(Class<? extends SubstitutionGuard> guardClass) {
         if (guardClass != SubstitutionGuard.class) {
             Constructor<?>[] constructors = guardClass.getConstructors();
@@ -612,20 +607,26 @@
          * Builds the initial graph for a snippet.
          */
         protected StructuredGraph buildInitialGraph(final ResolvedJavaMethod methodToParse) {
-            final StructuredGraph graph = new StructuredGraph(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, AllowAssumptions.NO);
+
+            // They will also never be never be evolved or have breakpoints set in them
+            graph.disableMethodRecording();
+
             try (Scope s = Debug.scope("buildInitialGraph", graph)) {
                 MetaAccessProvider metaAccess = replacements.providers.getMetaAccess();
 
                 if (MethodsElidedInSnippets != null && methodToParse.getSignature().getReturnKind() == Kind.Void && MethodFilter.matches(MethodsElidedInSnippets, methodToParse)) {
                     graph.addAfterFixed(graph.start(), graph.add(new ReturnNode(null)));
                 } else {
-                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.assumptions, replacements.providers.getConstantReflection(),
-                                    GraphBuilderConfiguration.getSnippetDefault(), OptimisticOptimizations.NONE).apply(graph);
+                    createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), GraphBuilderConfiguration.getSnippetDefault(),
+                                    OptimisticOptimizations.NONE).apply(graph);
                 }
                 afterParsing(graph);
 
                 if (OptCanonicalizer.getValue()) {
-                    new CanonicalizerPhase(true).apply(graph, new PhaseContext(replacements.providers, replacements.assumptions));
+                    new CanonicalizerPhase(true).apply(graph, new PhaseContext(replacements.providers));
                 }
             } catch (Throwable e) {
                 throw Debug.handle(e);
@@ -633,9 +634,9 @@
             return graph;
         }
 
-        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, assumptions, constantReflection, graphBuilderConfig, optimisticOpts);
+        protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
+                        OptimisticOptimizations optimisticOpts) {
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts);
         }
 
         protected void afterParsing(StructuredGraph graph) {
@@ -657,7 +658,7 @@
          */
         protected void afterInline(StructuredGraph caller, StructuredGraph callee, Object beforeInlineData) {
             if (OptCanonicalizer.getValue()) {
-                new CanonicalizerPhase(true).apply(caller, new PhaseContext(replacements.providers, replacements.assumptions));
+                new CanonicalizerPhase(true).apply(caller, new PhaseContext(replacements.providers));
             }
         }
 
@@ -668,7 +669,7 @@
             replacements.createNodeIntrinsificationPhase().apply(graph);
             new DeadCodeEliminationPhase(Optional).apply(graph);
             if (OptCanonicalizer.getValue()) {
-                new CanonicalizerPhase(true).apply(graph, new PhaseContext(replacements.providers, replacements.assumptions));
+                new CanonicalizerPhase(true).apply(graph, new PhaseContext(replacements.providers));
             }
         }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Thu Feb 12 20:47:20 2015 +0100
@@ -49,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.*;
@@ -561,10 +562,14 @@
         ResolvedJavaMethod method = snippetGraph.method();
         Signature signature = method.getSignature();
 
-        PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
+        PhaseContext phaseContext = new PhaseContext(providers);
 
         // Copy snippet graph, replacing constant parameters with given arguments
-        final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
+        final StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method(), AllowAssumptions.NO);
+        if (!snippetGraph.isMethodRecordingEnabled()) {
+            snippetCopy.disableMethodRecording();
+        }
+
         Map<Node, Node> nodeReplacements = Node.newIdentityMap();
         nodeReplacements.put(snippetGraph.start(), snippetCopy.start());
 
@@ -1245,7 +1250,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());
+            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.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -61,7 +61,7 @@
     /*
      * Looks at the given stamp and determines if it is an exact type (or can be assumed to be an
      * exact type) and if it is a cloneable type.
-     * 
+     *
      * If yes, then the exact type is returned, otherwise it returns null.
      */
     protected static ResolvedJavaType getConcreteType(Stamp stamp, Assumptions assumptions, MetaAccessProvider metaAccess) {
@@ -105,7 +105,7 @@
             } else {
                 obj = tool.getReplacedValue(getObject());
             }
-            ResolvedJavaType type = getConcreteType(obj.stamp(), tool.getAssumptions(), tool.getMetaAccessProvider());
+            ResolvedJavaType type = getConcreteType(obj.stamp(), graph().getAssumptions(), tool.getMetaAccessProvider());
             if (type != null && !type.isArray()) {
                 VirtualInstanceNode newVirtual = createVirtualInstanceNode(type, true);
                 ResolvedJavaField[] fields = newVirtual.getFields();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -129,7 +129,7 @@
      * @param replacementGraph a replacement (i.e., snippet or method substitution) graph
      */
     protected StructuredGraph lowerReplacement(final StructuredGraph replacementGraph, LoweringTool tool) {
-        final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.assumptions(), tool.getStampProvider());
+        final PhaseContext c = new PhaseContext(tool.getMetaAccess(), tool.getConstantReflection(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider());
         if (!graph().hasValueProxies()) {
             new RemoveValueProxyPhase().apply(replacementGraph);
         }
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Thu Feb 12 20:47:20 2015 +0100
@@ -47,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.*;
@@ -176,17 +177,16 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
         Suites suites = suitesProvider.createSuites();
-        LowLevelSuites lowLevelSuites = suitesProvider.createLowLevelSuites();
+        LIRSuites lirSuites = suitesProvider.createLIRSuites();
         removeInliningPhase(suites);
-        StructuredGraph graph = new StructuredGraph(javaMethod);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), GraphBuilderConfiguration.getEagerDefault(),
-                        OptimisticOptimizations.ALL).apply(graph);
+        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);
         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         CompilationResultBuilderFactory factory = getOptimizedCallTargetInstrumentationFactory(backend.getTarget().arch.getName(), javaMethod);
         return compileGraph(graph, cc, javaMethod, providers, backend, providers.getCodeCache().getTarget(), null, graphBuilderSuite, OptimisticOptimizations.ALL, getProfilingInfo(graph), null,
-                        suites, lowLevelSuites, new CompilationResult(), factory);
+                        suites, lirSuites, new CompilationResult(), factory);
     }
 
     private static Providers getGraalProviders() {
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,11 +24,11 @@
 
 import org.junit.*;
 
-import com.oracle.graal.api.code.*;
 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.*;
@@ -53,18 +53,16 @@
     }
 
     protected OptimizedCallTarget compileHelper(String methodName, RootNode root, Object[] arguments) {
-        Assumptions assumptions = new Assumptions(true);
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
-        StructuredGraph actual = partialEval(compilable, arguments, assumptions);
-        truffleCompiler.compileMethodHelper(actual, assumptions, methodName, getSpeculationLog(), compilable);
+        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) {
-        Assumptions assumptions = new Assumptions(true);
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
-        StructuredGraph actual = partialEval(compilable, arguments, assumptions);
-        truffleCompiler.compileMethodHelper(actual, assumptions, methodName, getSpeculationLog(), compilable);
+        StructuredGraph actual = partialEval(compilable, arguments, AllowAssumptions.YES);
+        truffleCompiler.compileMethodHelper(actual, methodName, null, getSpeculationLog(), compilable);
         removeFrameStates(actual);
         StructuredGraph expected = parseForComparison(methodName);
         Assert.assertEquals(getCanonicalGraphString(expected, true, true), getCanonicalGraphString(actual, true, true));
@@ -76,23 +74,22 @@
     }
 
     protected void assertPartialEvalNoInvokes(RootNode root, Object[] arguments) {
-        Assumptions assumptions = new Assumptions(true);
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
-        StructuredGraph actual = partialEval(compilable, arguments, 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, final Assumptions assumptions) {
+    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, assumptions);
+            return truffleCompiler.getPartialEvaluator().createGraph(compilable, allowAssumptions, null);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
@@ -103,13 +100,13 @@
             frameState.replaceAtUsages(null);
             frameState.safeDelete();
         }
-        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders(), new Assumptions(false)));
+        new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
         new DeadCodeEliminationPhase().apply(graph);
     }
 
     protected StructuredGraph parseForComparison(final String methodName) {
         try (Scope s = Debug.scope("Truffle", new DebugDumpScope("Comparison: " + methodName))) {
-            StructuredGraph graph = parseEager(methodName);
+            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/FrameWithoutBoxing.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,13 +22,11 @@
  */
 package com.oracle.graal.truffle;
 
-import java.nio.*;
 import java.lang.reflect.*;
 import java.util.*;
 
 import sun.misc.*;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 
@@ -107,9 +105,9 @@
     }
 
     private byte getByteUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Byte);
+        long offset = getPrimitiveOffset(slot);
         boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Byte.ordinal();
-        return unsafeGetByte(getPrimitiveLocals(), offset, condition, slot);
+        return (byte) unsafeGetInt(getPrimitiveLocals(), offset, condition, slot);
     }
 
     @Override
@@ -119,8 +117,8 @@
     }
 
     private void setByteUnsafe(FrameSlot slot, byte value) {
-        long offset = alignPrimitive(slot, Kind.Boolean);
-        unsafePutByte(getPrimitiveLocals(), offset, value, slot);
+        long offset = getPrimitiveOffset(slot);
+        unsafePutInt(getPrimitiveLocals(), offset, value, slot);
     }
 
     @Override
@@ -130,9 +128,9 @@
     }
 
     private boolean getBooleanUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Boolean);
+        long offset = getPrimitiveOffset(slot);
         boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Boolean.ordinal();
-        return unsafeGetBoolean(getPrimitiveLocals(), offset, condition, slot);
+        return unsafeGetInt(getPrimitiveLocals(), offset, condition, slot) != 0;
     }
 
     @Override
@@ -142,8 +140,8 @@
     }
 
     private void setBooleanUnsafe(FrameSlot slot, boolean value) {
-        long offset = alignPrimitive(slot, Kind.Boolean);
-        unsafePutBoolean(getPrimitiveLocals(), offset, value, slot);
+        long offset = getPrimitiveOffset(slot);
+        unsafePutInt(getPrimitiveLocals(), offset, value ? 1 : 0, slot);
     }
 
     @Override
@@ -153,7 +151,7 @@
     }
 
     private float getFloatUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Float);
+        long offset = getPrimitiveOffset(slot);
         boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Float.ordinal();
         return unsafeGetFloat(getPrimitiveLocals(), offset, condition, slot);
     }
@@ -165,7 +163,7 @@
     }
 
     private void setFloatUnsafe(FrameSlot slot, float value) {
-        long offset = alignPrimitive(slot, Kind.Float);
+        long offset = getPrimitiveOffset(slot);
         unsafePutFloat(getPrimitiveLocals(), offset, value, slot);
     }
 
@@ -176,7 +174,7 @@
     }
 
     private long getLongUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Long);
+        long offset = getPrimitiveOffset(slot);
         boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Long.ordinal();
         return unsafeGetLong(getPrimitiveLocals(), offset, condition, slot);
     }
@@ -188,7 +186,7 @@
     }
 
     private void setLongUnsafe(FrameSlot slot, long value) {
-        long offset = alignPrimitive(slot, Kind.Long);
+        long offset = getPrimitiveOffset(slot);
         unsafePutLong(getPrimitiveLocals(), offset, value, slot);
     }
 
@@ -199,7 +197,7 @@
     }
 
     private int getIntUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Int);
+        long offset = getPrimitiveOffset(slot);
         boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Int.ordinal();
         return unsafeGetInt(getPrimitiveLocals(), offset, condition, slot);
     }
@@ -211,7 +209,7 @@
     }
 
     private void setIntUnsafe(FrameSlot slot, int value) {
-        long offset = alignPrimitive(slot, Kind.Int);
+        long offset = getPrimitiveOffset(slot);
         unsafePutInt(getPrimitiveLocals(), offset, value, slot);
     }
 
@@ -222,7 +220,7 @@
     }
 
     private double getDoubleUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Double);
+        long offset = getPrimitiveOffset(slot);
         boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Double.ordinal();
         return unsafeGetDouble(getPrimitiveLocals(), offset, condition, slot);
     }
@@ -234,7 +232,7 @@
     }
 
     private void setDoubleUnsafe(FrameSlot slot, double value) {
-        long offset = alignPrimitive(slot, Kind.Double);
+        long offset = getPrimitiveOffset(slot);
         unsafePutDouble(getPrimitiveLocals(), offset, value, slot);
     }
 
@@ -269,14 +267,8 @@
         }
     }
 
-    private static long alignPrimitive(FrameSlot slot, Kind forKind) {
-        long offset = Unsafe.ARRAY_LONG_BASE_OFFSET + slot.getIndex() * (long) Unsafe.ARRAY_LONG_INDEX_SCALE;
-        if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
-            // On big endian, we use int in long type, which means, when byteCount() <=4, the value
-            // is right aligned in the 4 byte half, which has the lower address.
-            offset += Kind.Long.getByteCount() - Math.min((long) Unsafe.ARRAY_LONG_INDEX_SCALE, 4 + forKind.getByteCount());
-        }
-        return offset;
+    private static long getPrimitiveOffset(FrameSlot slot) {
+        return Unsafe.ARRAY_LONG_BASE_OFFSET + slot.getIndex() * (long) Unsafe.ARRAY_LONG_INDEX_SCALE;
     }
 
     @Override
@@ -368,16 +360,6 @@
     }
 
     @SuppressWarnings("unused")
-    static boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getBoolean(receiver, offset);
-    }
-
-    @SuppressWarnings("unused")
-    static byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getByte(receiver, offset);
-    }
-
-    @SuppressWarnings("unused")
     static int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
         return UNSAFE.getInt(receiver, offset);
     }
@@ -403,16 +385,6 @@
     }
 
     @SuppressWarnings("unused")
-    static void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity) {
-        UNSAFE.putBoolean(receiver, offset, value);
-    }
-
-    @SuppressWarnings("unused")
-    static void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity) {
-        UNSAFE.putByte(receiver, offset, value);
-    }
-
-    @SuppressWarnings("unused")
     static void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity) {
         UNSAFE.putInt(receiver, offset, value);
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Thu Feb 12 20:47:20 2015 +0100
@@ -34,10 +34,12 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.truffle.debug.*;
+import com.oracle.graal.truffle.unsafe.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.unsafe.*;
 
 public abstract class GraalTruffleRuntime implements TruffleRuntime {
 
@@ -181,6 +183,9 @@
     }
 
     public <T> T getCapability(Class<T> capability) {
+        if (capability == UnsafeAccessFactory.class) {
+            return capability.cast(new UnsafeAccessFactoryImpl());
+        }
         return null;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Feb 12 20:47:20 2015 +0100
@@ -30,7 +30,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
@@ -41,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.*;
@@ -97,7 +97,7 @@
         }
     }
 
-    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) {
+    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions, GraphBuilderPlugins graalPlugins) {
         if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) {
             constantReceivers = new HashSet<>();
         }
@@ -108,7 +108,7 @@
             throw Debug.handle(e);
         }
 
-        final StructuredGraph graph = new StructuredGraph(callTarget.toString(), callRootMethod);
+        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)) {
@@ -117,14 +117,14 @@
             if (CacheGraphs.getValue()) {
                 graphCache = new HashMap<>();
             }
-            PhaseContext baseContext = new PhaseContext(providers, assumptions);
-            HighTierContext tierContext = new HighTierContext(providers, assumptions, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
+            PhaseContext baseContext = new PhaseContext(providers);
+            HighTierContext tierContext = new HighTierContext(providers, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
 
             if (TruffleCompilerOptions.FastPE.getValue()) {
-                fastPartialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
+                fastPartialEvaluation(callTarget, graph, baseContext, tierContext, graalPlugins);
             } else {
                 createRootGraph(graph);
-                partialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
+                partialEvaluation(callTarget, graph, baseContext, tierContext);
             }
 
             if (Thread.currentThread().isInterrupted()) {
@@ -207,20 +207,16 @@
     }
 
     @SuppressWarnings("unused")
-    private void fastPartialEvaluation(OptimizedCallTarget callTarget, Assumptions assumptions, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
+    private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext, GraphBuilderPlugins graalPlugins) {
         GraphBuilderConfiguration newConfig = configForRoot.copy();
         newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
         newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
         newConfig.setInlineInvokePlugin(new InlineInvokePlugin());
         newConfig.setLoopExplosionPlugin(new LoopExplosionPlugin());
-        DefaultGraphBuilderPlugins plugins = new DefaultGraphBuilderPlugins();
-        Iterable<GraphBuilderPluginsProvider> sl = Services.load(GraphBuilderPluginsProvider.class);
-        for (GraphBuilderPluginsProvider p : sl) {
-            p.registerPlugins(providers.getMetaAccess(), plugins);
-        }
+        DefaultGraphBuilderPlugins plugins = graalPlugins == null ? new DefaultGraphBuilderPlugins() : graalPlugins.copy();
         TruffleGraphBuilderPlugins.registerPlugins(providers.getMetaAccess(), plugins);
         long ms = System.currentTimeMillis();
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(true), this.snippetReflection, providers.getConstantReflection(), newConfig, plugins,
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig, plugins,
                         TruffleCompilerImpl.Optimizations).apply(graph);
         System.out.println("# ms: " + (System.currentTimeMillis() - ms));
         Debug.dump(graph, "After FastPE");
@@ -234,7 +230,7 @@
         }
     }
 
-    private void partialEvaluation(final OptimizedCallTarget callTarget, final Assumptions assumptions, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
+    private void partialEvaluation(final OptimizedCallTarget callTarget, final StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext) {
         injectConstantCallTarget(graph, callTarget, baseContext);
 
         Debug.dump(graph, "Before expansion");
@@ -244,7 +240,7 @@
             expansionLogger = new TruffleExpansionLogger(providers, graph);
         }
 
-        expandTree(graph, assumptions, expansionLogger);
+        expandTree(graph, expansionLogger);
 
         TruffleInliningCache inliningCache = null;
         if (TruffleFunctionInlining.getValue()) {
@@ -254,7 +250,7 @@
             }
         }
 
-        expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache);
+        expandDirectCalls(graph, expansionLogger, callTarget.getInlining(), inliningCache);
 
         if (Thread.currentThread().isInterrupted()) {
             return;
@@ -269,7 +265,7 @@
             } catch (Throwable t) {
                 Debug.handle(t);
             }
-        } while (expandTree(graph, assumptions, expansionLogger));
+        } while (expandTree(graph, expansionLogger));
 
         if (expansionLogger != null) {
             expansionLogger.print(callTarget);
@@ -277,15 +273,13 @@
     }
 
     public StructuredGraph createRootGraph(StructuredGraph graph) {
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot,
-                        TruffleCompilerImpl.Optimizations).apply(graph);
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), configForRoot, TruffleCompilerImpl.Optimizations).apply(graph);
         return graph;
     }
 
-    public StructuredGraph createInlineGraph(String name) {
-        StructuredGraph graph = new StructuredGraph(name, callInlinedMethod);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), configForRoot,
-                        TruffleCompilerImpl.Optimizations).apply(graph);
+    public StructuredGraph createInlineGraph(String name, StructuredGraph caller) {
+        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;
     }
 
@@ -341,8 +335,8 @@
         new DebugHistogramAsciiPrinter(TTY.out().out()).print(histogram);
     }
 
-    private boolean expandTree(StructuredGraph graph, Assumptions assumptions, TruffleExpansionLogger expansionLogger) {
-        PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+    private boolean expandTree(StructuredGraph graph, TruffleExpansionLogger expansionLogger) {
+        PhaseContext phaseContext = new PhaseContext(providers);
         boolean changed = false;
         boolean changedInIteration;
         ArrayDeque<MethodCallTargetNode> queue = new ArrayDeque<>();
@@ -483,18 +477,18 @@
         }
     }
 
-    private void expandDirectCalls(StructuredGraph graph, Assumptions assumptions, TruffleExpansionLogger expansionLogger, TruffleInlining inlining, TruffleInliningCache inliningCache) {
-        PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+    private void expandDirectCalls(StructuredGraph graph, TruffleExpansionLogger expansionLogger, TruffleInlining inlining, TruffleInliningCache inliningCache) {
+        PhaseContext phaseContext = new PhaseContext(providers);
 
         for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
-            StructuredGraph inlineGraph = parseDirectCallGraph(phaseContext, assumptions, inlining, inliningCache, methodCallTargetNode);
+            StructuredGraph inlineGraph = parseDirectCallGraph(phaseContext, graph, inlining, inliningCache, methodCallTargetNode);
 
             if (inlineGraph != null) {
                 expandTreeInline(graph, phaseContext, expansionLogger, methodCallTargetNode, inlineGraph);
             }
         }
         // non inlined direct calls need to be expanded until TruffleCallBoundary.
-        expandTree(graph, assumptions, expansionLogger);
+        expandTree(graph, expansionLogger);
         assert noDirectCallsLeft(graph);
     }
 
@@ -507,7 +501,7 @@
         return true;
     }
 
-    private StructuredGraph parseDirectCallGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInlining inlining, TruffleInliningCache inliningCache,
+    private StructuredGraph parseDirectCallGraph(PhaseContext phaseContext, StructuredGraph caller, TruffleInlining inlining, TruffleInliningCache inliningCache,
                     MethodCallTargetNode methodCallTargetNode) {
         OptimizedDirectCallNode callNode = resolveConstantCallNode(methodCallTargetNode);
         if (callNode == null) {
@@ -536,13 +530,13 @@
         StructuredGraph graph;
         if (decision != null && decision.isInline()) {
             if (inliningCache == null) {
-                graph = createInlineGraph(phaseContext, assumptions, null, decision);
+                graph = createInlineGraph(phaseContext, caller, null, decision);
             } else {
-                graph = inliningCache.getCachedGraph(phaseContext, assumptions, decision);
+                graph = inliningCache.getCachedGraph(phaseContext, caller, decision);
             }
             decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount());
 
-            assumptions.record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
+            caller.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
         } else {
             // we continue expansion of callDirect until we reach the callBoundary.
             graph = parseGraph(methodCallTargetNode.targetMethod(), methodCallTargetNode.arguments(), phaseContext);
@@ -591,17 +585,17 @@
         return (OptimizedDirectCallNode) value;
     }
 
-    private StructuredGraph createInlineGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningCache cache, TruffleInliningDecision decision) {
+    private StructuredGraph createInlineGraph(PhaseContext phaseContext, StructuredGraph caller, TruffleInliningCache cache, TruffleInliningDecision decision) {
         try (Scope s = Debug.scope("GuestLanguageInlinedGraph", new DebugDumpScope(decision.getTarget().toString()))) {
             OptimizedCallTarget target = decision.getTarget();
-            StructuredGraph inlineGraph = createInlineGraph(target.toString());
+            StructuredGraph inlineGraph = createInlineGraph(target.toString(), caller);
             injectConstantCallTarget(inlineGraph, decision.getTarget(), phaseContext);
             TruffleExpansionLogger expansionLogger = null;
             if (TraceTruffleExpansion.getValue()) {
                 expansionLogger = new TruffleExpansionLogger(providers, inlineGraph);
             }
-            expandTree(inlineGraph, assumptions, expansionLogger);
-            expandDirectCalls(inlineGraph, assumptions, expansionLogger, decision, cache);
+            expandTree(inlineGraph, expansionLogger);
+            expandDirectCalls(inlineGraph, expansionLogger, decision, cache);
 
             if (expansionLogger != null) {
                 expansionLogger.print(target);
@@ -632,11 +626,11 @@
             this.cache = new HashMap<>();
         }
 
-        public StructuredGraph getCachedGraph(PhaseContext phaseContext, Assumptions assumptions, TruffleInliningDecision decision) {
+        public StructuredGraph getCachedGraph(PhaseContext phaseContext, StructuredGraph caller, TruffleInliningDecision decision) {
             CacheKey cacheKey = new CacheKey(decision);
             StructuredGraph inlineGraph = cache.get(cacheKey);
             if (inlineGraph == null) {
-                inlineGraph = createInlineGraph(phaseContext, assumptions, this, decision);
+                inlineGraph = createInlineGraph(phaseContext, caller, this, decision);
                 cache.put(cacheKey, inlineGraph);
             }
             return inlineGraph;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -25,7 +25,6 @@
 import java.util.*;
 import java.util.Map.Entry;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -35,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.*;
@@ -60,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();
+    private final StructuredGraph markerGraph = new StructuredGraph(AllowAssumptions.NO);
 
     private final ResolvedJavaType stringBuilderClass;
     private final ResolvedJavaType runtimeExceptionClass;
@@ -119,11 +119,11 @@
             lookupExceedsMaxSize();
         }
 
-        StructuredGraph graph;
-        PhaseContext phaseContext = new PhaseContext(providers, new Assumptions(false));
+        StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO);
+        PhaseContext phaseContext = new PhaseContext(providers);
         try (Scope s = Debug.scope("TruffleCache", providers.getMetaAccess(), method)) {
 
-            graph = parseGraph(method, phaseContext);
+            graph = parseGraph(graph, phaseContext);
             if (graph == null) {
                 return null;
             }
@@ -268,9 +268,8 @@
         canonicalizer.applyIncremental(graph, phaseContext, canonicalizerUsages);
     }
 
-    protected StructuredGraph parseGraph(final ResolvedJavaMethod method, final PhaseContext phaseContext) {
-        final StructuredGraph graph = new StructuredGraph(method);
-        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), phaseContext.getAssumptions(), null, config, optimisticOptimizations).apply(graph);
+    protected StructuredGraph parseGraph(StructuredGraph graph, final PhaseContext phaseContext) {
+        new GraphBuilderPhase.Instance(phaseContext.getMetaAccess(), phaseContext.getStampProvider(), null, config, optimisticOptimizations).apply(graph);
         return graph;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -27,8 +27,8 @@
 
 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.*;
@@ -42,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.*;
@@ -60,7 +61,7 @@
 
     private final Providers providers;
     private final Suites suites;
-    private final LowLevelSuites lowLevelSuites;
+    private final LIRSuites lirSuites;
     private final PartialEvaluator partialEvaluator;
     private final Backend backend;
     private final GraphBuilderConfiguration config;
@@ -83,7 +84,7 @@
         ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backend.getProviders().getConstantReflection(), backend.getProviders().getMetaAccess());
         this.providers = backend.getProviders().copyWith(truffleReplacements).copyWith(constantReflection);
         this.suites = backend.getSuites().getDefaultSuites();
-        this.lowLevelSuites = backend.getSuites().getDefaultLowLevelSuites();
+        this.lirSuites = backend.getSuites().getDefaultLIRSuites();
 
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
@@ -119,10 +120,10 @@
         compilationNotify.notifyCompilationStarted(compilable);
 
         try {
-            Assumptions assumptions = new Assumptions(true);
+            GraphBuilderSuiteInfo info = createGraphBuilderSuite();
 
             try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
-                graph = partialEvaluator.createGraph(compilable, assumptions);
+                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES, info.plugins);
             }
 
             if (Thread.currentThread().isInterrupted()) {
@@ -137,7 +138,7 @@
             }
 
             compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
-            CompilationResult compilationResult = compileMethodHelper(graph, assumptions, compilable.toString(), compilable.getSpeculationLog(), compilable);
+            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), info.suite, compilable.getSpeculationLog(), compilable);
             compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
         } catch (Throwable t) {
             compilationNotify.notifyCompilationFailed(compilable, graph, t);
@@ -145,7 +146,7 @@
         }
     }
 
-    public CompilationResult compileMethodHelper(StructuredGraph graph, Assumptions assumptions, String name, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
+    public CompilationResult compileMethodHelper(StructuredGraph graph, String name, PhaseSuite<HighTierContext> graphBuilderSuite, SpeculationLog speculationLog, InstalledCode predefinedInstalledCode) {
         try (Scope s = Debug.scope("TruffleFinal")) {
             Debug.dump(1, graph, "After TruffleTier");
         } catch (Throwable e) {
@@ -157,29 +158,34 @@
             CodeCacheProvider codeCache = providers.getCodeCache();
             CallingConvention cc = getCallingConvention(codeCache, Type.JavaCallee, graph.method(), false);
             CompilationResult compilationResult = new CompilationResult(name);
-            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, createGraphBuilderSuite(), Optimizations, getProfilingInfo(graph), speculationLog,
-                            suites, lowLevelSuites, compilationResult, CompilationResultBuilderFactory.Default);
+            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, graphBuilderSuite == null ? createGraphBuilderSuite().suite : graphBuilderSuite,
+                            Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites, compilationResult, CompilationResultBuilderFactory.Default);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
 
         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<>();
-        Assumptions newAssumptions = new Assumptions(true);
-        if (assumptions != null) {
-            for (Assumption assumption : assumptions.getAssumptions()) {
+        Set<Assumption> newAssumptions = new HashSet<>();
+        for (Assumption assumption : graph.getAssumptions()) {
+            processAssumption(newAssumptions, assumption, validAssumptions);
+        }
+
+        if (result.getAssumptions() != null) {
+            for (Assumption assumption : result.getAssumptions()) {
                 processAssumption(newAssumptions, assumption, validAssumptions);
             }
         }
 
-        if (result.getAssumptions() != null) {
-            for (Assumption assumption : result.getAssumptions().getAssumptions()) {
-                processAssumption(newAssumptions, assumption, validAssumptions);
-            }
-        }
-
-        result.setAssumptions(newAssumptions);
+        result.setAssumptions(newAssumptions.toArray(new Assumption[newAssumptions.size()]));
 
         InstalledCode installedCode;
         try (Scope s = Debug.scope("CodeInstall", providers.getCodeCache()); TimerCloseable a = CodeInstallationTime.start(); Closeable c = CodeInstallationMemUse.start()) {
@@ -198,22 +204,33 @@
         return result;
     }
 
-    private PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+    static class GraphBuilderSuiteInfo {
+        final PhaseSuite<HighTierContext> suite;
+        final GraphBuilderPlugins plugins;
+
+        public GraphBuilderSuiteInfo(PhaseSuite<HighTierContext> suite, GraphBuilderPlugins plugins) {
+            this.suite = suite;
+            this.plugins = plugins;
+        }
+    }
+
+    private GraphBuilderSuiteInfo createGraphBuilderSuite() {
         PhaseSuite<HighTierContext> suite = backend.getSuites().getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
         GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) iterator.previous();
         iterator.remove();
-        iterator.add(new GraphBuilderPhase(config, graphBuilderPhase.getGraphBuilderPlugins()));
-        return suite;
+        GraphBuilderPlugins plugins = graphBuilderPhase.getGraphBuilderPlugins();
+        iterator.add(new GraphBuilderPhase(config, plugins));
+        return new GraphBuilderSuiteInfo(suite, plugins);
     }
 
-    public void processAssumption(Assumptions newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
+    public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
         if (assumption != null) {
             if (assumption instanceof AssumptionValidAssumption) {
                 AssumptionValidAssumption assumptionValidAssumption = (AssumptionValidAssumption) assumption;
                 manual.add(assumptionValidAssumption);
             } else {
-                newAssumptions.record(assumption);
+                newAssumptions.add(assumption);
             }
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Thu Feb 12 20:47:20 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.truffle.substitutions.*;
+import com.oracle.graal.truffle.unsafe.*;
 import com.oracle.truffle.api.*;
 
 /**
@@ -42,7 +43,7 @@
     private final Replacements graalReplacements;
 
     protected TruffleReplacements(Providers providers, SnippetReflectionProvider snippetReflection) {
-        super(providers, snippetReflection, providers.getReplacements().getAssumptions(), providers.getCodeCache().getTarget());
+        super(providers, snippetReflection, providers.getCodeCache().getTarget());
         this.graalReplacements = providers.getReplacements();
 
         registerTruffleSubstitutions();
@@ -55,6 +56,7 @@
         registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
         registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class);
         registerSubstitutions(FrameWithoutBoxing.class, FrameWithoutBoxingSubstitutions.class);
+        registerSubstitutions(UnsafeAccessImpl.class, UnsafeAccessSubstitutions.class);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.truffle.nodes;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
@@ -62,14 +63,15 @@
     @Override
     public void simplify(SimplifierTool tool) {
         ValueNode assumption = getAssumption();
-        if (tool.assumptions() != null && assumption.isConstant()) {
+        Assumptions assumptions = graph().getAssumptions();
+        if (assumption.isConstant()) {
             JavaConstant c = assumption.asJavaConstant();
             assert c.getKind() == Kind.Object;
             Object object = getSnippetReflection().asObject(Object.class, c);
             OptimizedAssumption assumptionObject = (OptimizedAssumption) object;
             StructuredGraph graph = graph();
             if (assumptionObject.isValid()) {
-                tool.assumptions().record(new AssumptionValidAssumption(assumptionObject));
+                assumptions.record(new AssumptionValidAssumption(assumptionObject));
                 if (super.getReturnType().getKind() == Kind.Boolean) {
                     graph.replaceFixedWithFloating(this, ConstantNode.forBoolean(true, graph()));
                 } else {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -172,7 +172,7 @@
             for (int i = 0; i < frameSize; i++) {
                 primitiveArrayEntryState[i] = initialPrimitiveValue(frameDescriptor.getSlots().get(i).getKind());
             }
-            tool.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
+            graph().getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
         }
 
         tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList());
@@ -195,11 +195,7 @@
         Kind graalKind = null;
         switch (kind) {
             case Boolean:
-                graalKind = Kind.Boolean;
-                break;
             case Byte:
-                graalKind = Kind.Byte;
-                break;
             case Int:
                 graalKind = Kind.Int;
                 break;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2014, 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.graal.truffle.nodes.typesystem;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.truffle.nodes.*;
-
-/**
- * Load of a final value from a location specified as an offset relative to an object.
- *
- * Substitution for method CompilerDirectives#unsafeGet*.
- */
-@NodeInfo
-public final class CustomizedUnsafeLoadFinalNode extends FixedWithNextNode implements Canonicalizable, Virtualizable, Lowerable {
-    @Input ValueNode object;
-    @Input ValueNode offset;
-    @Input ValueNode condition;
-    @Input ValueNode location;
-    protected final Kind accessKind;
-
-    public CustomizedUnsafeLoadFinalNode(ValueNode object, ValueNode offset, ValueNode condition, ValueNode location, Kind accessKind) {
-        super(StampFactory.forKind(accessKind.getStackKind()));
-        this.object = object;
-        this.offset = offset;
-        this.condition = condition;
-        this.location = location;
-        this.accessKind = accessKind;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (object.isConstant() && !object.isNullConstant() && offset.isConstant() && condition.isConstant() && condition.asJavaConstant().asInt() == 1) {
-            JavaConstant constant = tool.getConstantReflection().getMemoryAccessProvider().readUnsafeConstant(accessKind, object.asJavaConstant(), offset.asJavaConstant().asLong());
-            return ConstantNode.forConstant(constant, tool.getMetaAccess());
-        }
-        return this;
-    }
-
-    /**
-     * @see UnsafeLoadNode#virtualize(VirtualizerTool)
-     */
-    @Override
-    public void virtualize(VirtualizerTool tool) {
-        State state = tool.getObjectState(object);
-        if (state != null && state.getState() == EscapeState.Virtual) {
-            ValueNode offsetValue = tool.getReplacedValue(offset);
-            if (offsetValue.isConstant()) {
-                long constantOffset = offsetValue.asJavaConstant().asLong();
-                int entryIndex = state.getVirtualObject().entryIndexForOffset(constantOffset, accessKind);
-                if (entryIndex != -1) {
-                    ValueNode entry = state.getEntry(entryIndex);
-                    if (entry.getKind() == getKind() || state.getVirtualObject().entryKind(entryIndex) == accessKind) {
-                        tool.replaceWith(entry);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void lower(LoweringTool tool) {
-        LogicNode compare = CompareNode.createCompareNode(graph(), Condition.EQ, condition, ConstantNode.forBoolean(true, graph()), tool.getConstantReflection());
-        LocationIdentity locationIdentity;
-        if (!location.isConstant() || location.isNullConstant()) {
-            locationIdentity = LocationIdentity.ANY_LOCATION;
-        } else {
-            locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
-        }
-        UnsafeLoadNode result = graph().add(new UnsafeLoadNode(object, offset, accessKind, locationIdentity, compare));
-        graph().replaceFixedWithFixed(this, result);
-        result.lower(tool);
-    }
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static <T> T load(Object object, long offset, boolean condition, Object locationIdentity, @ConstantNodeParameter Kind kind) {
-        return UnsafeLoadNode.load(object, offset, kind, null);
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Thu Feb 12 20:47:20 2015 +0100
@@ -31,7 +31,6 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.truffle.nodes.*;
 import com.oracle.graal.truffle.nodes.frame.*;
-import com.oracle.graal.truffle.nodes.typesystem.*;
 import com.oracle.truffle.api.*;
 
 @ClassSubstitution(CompilerDirectives.class)
@@ -77,100 +76,8 @@
     @MacroSubstitution(macro = IsCompilationConstantNode.class, isStatic = true)
     public static native boolean isCompilationConstant(Object value);
 
-    @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true)
-    public static native Object unsafeCast(Object value, Class<?> clazz, boolean condition, boolean nonNull);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity);
-
-    @MethodSubstitution
-    public static boolean unsafeGetFinalBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Boolean);
-    }
-
-    @MethodSubstitution
-    public static byte unsafeGetFinalByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Byte);
-    }
-
-    @MethodSubstitution
-    public static short unsafeGetFinalShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Short);
-    }
-
-    @MethodSubstitution
-    public static int unsafeGetFinalInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Int);
-    }
-
-    @MethodSubstitution
-    public static long unsafeGetFinalLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Long);
-    }
-
-    @MethodSubstitution
-    public static float unsafeGetFinalFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Float);
-    }
-
-    @MethodSubstitution
-    public static double unsafeGetFinalDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Double);
-    }
-
-    @MethodSubstitution
-    public static Object unsafeGetFinalObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return CustomizedUnsafeLoadFinalNode.load(receiver, offset, condition, locationIdentity, Kind.Object);
-    }
-
     @MethodSubstitution
     public static void materialize(Object obj) {
         ForceMaterializeNode.force(obj);
     }
-
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Thu Feb 12 20:47:20 2015 +0100
@@ -41,12 +41,6 @@
     public static native Object unsafeCast(Object value, Class<?> clazz, boolean condition, boolean nonNull);
 
     @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
-    public static native byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
     public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity);
 
     @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
@@ -62,12 +56,6 @@
     public static native Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity);
 
     @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
-    public static native void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity);
-
-    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
     public static native void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity);
 
     @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Thu Feb 12 20:47:20 2015 +0100
@@ -42,6 +42,7 @@
 import com.oracle.graal.truffle.nodes.*;
 import com.oracle.graal.truffle.nodes.arithmetic.*;
 import com.oracle.graal.truffle.nodes.frame.*;
+import com.oracle.graal.truffle.unsafe.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 
@@ -189,7 +190,16 @@
                 throw GraalInternalError.shouldNotReachHere("unsafeCast arguments could not reduce to a constant: " + clazz + ", " + nonNull);
             }
         });
-        for (Kind kind : new Kind[]{Kind.Boolean, Kind.Byte, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object}) {
+
+        registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+
+        // CompilerDirectives.class
+        r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
+        registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+    }
+
+    protected static void registerUnsafeLoadStorePlugins(Registration r, Kind... kinds) {
+        for (Kind kind : kinds) {
             String kindName = kind.getJavaName();
             kindName = toUpperCase(kindName.charAt(0)) + kindName.substring(1);
             String getName = "unsafeGet" + kindName;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnsafeAccessSubstitutions.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.substitutions;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.truffle.nodes.typesystem.*;
+import com.oracle.graal.truffle.unsafe.*;
+
+@ClassSubstitution(UnsafeAccessImpl.class)
+public class UnsafeAccessSubstitutions {
+    @MacroSubstitution(macro = UnsafeTypeCastMacroNode.class, isStatic = true)
+    public static native Object unsafeCast(Object value, Class<?> clazz, boolean condition, boolean nonNull);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeLoadMacroNode.class, isStatic = true)
+    public static native Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity);
+
+    @MacroSubstitution(macro = CustomizedUnsafeStoreMacroNode.class, isStatic = true)
+    public static native void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/unsafe/UnsafeAccessFactoryImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.unsafe;
+
+import sun.misc.*;
+
+import com.oracle.truffle.api.unsafe.*;
+
+public final class UnsafeAccessFactoryImpl implements UnsafeAccessFactory {
+    public UnsafeAccess createUnsafeAccess(Unsafe unsafe) {
+        return new UnsafeAccessImpl(unsafe);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/unsafe/UnsafeAccessImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.unsafe;
+
+import java.lang.reflect.*;
+
+import sun.misc.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.unsafe.*;
+
+@SuppressWarnings("unused")
+public final class UnsafeAccessImpl implements UnsafeAccess {
+    public UnsafeAccessImpl(Unsafe unsafe) {
+    }
+
+    public <T> T uncheckedCast(Object value, Class<T> type, boolean condition, boolean nonNull) {
+        return unsafeCast(value, type, condition, nonNull);
+    }
+
+    public boolean getBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetBoolean(receiver, offset, condition, locationIdentity);
+    }
+
+    public byte getByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetByte(receiver, offset, condition, locationIdentity);
+    }
+
+    public short getShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetShort(receiver, offset, condition, locationIdentity);
+    }
+
+    public int getInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetInt(receiver, offset, condition, locationIdentity);
+    }
+
+    public long getLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetLong(receiver, offset, condition, locationIdentity);
+    }
+
+    public float getFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetFloat(receiver, offset, condition, locationIdentity);
+    }
+
+    public double getDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetDouble(receiver, offset, condition, locationIdentity);
+    }
+
+    public Object getObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return unsafeGetObject(receiver, offset, condition, locationIdentity);
+    }
+
+    public void putBoolean(Object receiver, long offset, boolean value, Object locationIdentity) {
+        unsafePutBoolean(receiver, offset, value, locationIdentity);
+    }
+
+    public void putByte(Object receiver, long offset, byte value, Object locationIdentity) {
+        unsafePutByte(receiver, offset, value, locationIdentity);
+    }
+
+    public void putShort(Object receiver, long offset, short value, Object locationIdentity) {
+        unsafePutShort(receiver, offset, value, locationIdentity);
+    }
+
+    public void putInt(Object receiver, long offset, int value, Object locationIdentity) {
+        unsafePutInt(receiver, offset, value, locationIdentity);
+    }
+
+    public void putLong(Object receiver, long offset, long value, Object locationIdentity) {
+        unsafePutLong(receiver, offset, value, locationIdentity);
+    }
+
+    public void putFloat(Object receiver, long offset, float value, Object locationIdentity) {
+        unsafePutFloat(receiver, offset, value, locationIdentity);
+    }
+
+    public void putDouble(Object receiver, long offset, double value, Object locationIdentity) {
+        unsafePutDouble(receiver, offset, value, locationIdentity);
+    }
+
+    public void putObject(Object receiver, long offset, Object value, Object locationIdentity) {
+        unsafePutObject(receiver, offset, value, locationIdentity);
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull) {
+        return (T) value;
+    }
+
+    private static boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getBoolean(receiver, offset);
+    }
+
+    private static byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getByte(receiver, offset);
+    }
+
+    private static short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getShort(receiver, offset);
+    }
+
+    private static int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getInt(receiver, offset);
+    }
+
+    private static long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getLong(receiver, offset);
+    }
+
+    private static float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getFloat(receiver, offset);
+    }
+
+    private static double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getDouble(receiver, offset);
+    }
+
+    private static Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getObject(receiver, offset);
+    }
+
+    private static void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity) {
+        UNSAFE.putBoolean(receiver, offset, value);
+    }
+
+    private static void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity) {
+        UNSAFE.putByte(receiver, offset, value);
+    }
+
+    private static void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity) {
+        UNSAFE.putShort(receiver, offset, value);
+    }
+
+    private static void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity) {
+        UNSAFE.putInt(receiver, offset, value);
+    }
+
+    private static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) {
+        UNSAFE.putLong(receiver, offset, value);
+    }
+
+    private static void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity) {
+        UNSAFE.putFloat(receiver, offset, value);
+    }
+
+    private static void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity) {
+        UNSAFE.putDouble(receiver, offset, value);
+    }
+
+    private static void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity) {
+        UNSAFE.putObject(receiver, offset, value);
+    }
+
+    private static final Unsafe UNSAFE = getUnsafe();
+
+    private static Unsafe getUnsafe() {
+        try {
+            return Unsafe.getUnsafe();
+        } catch (SecurityException e) {
+        }
+        try {
+            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
+            theUnsafeInstance.setAccessible(true);
+            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
+        } catch (Exception e) {
+            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
+        }
+    }
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,7 +26,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -39,8 +38,8 @@
 
 public class PEReadEliminationClosure extends PartialEscapeClosure<PEReadEliminationBlockState> {
 
-    public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
-        super(schedule, metaAccess, constantReflection, assumptions);
+    public PEReadEliminationClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+        super(schedule, metaAccess, constantReflection);
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Thu Feb 12 20:47:20 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
@@ -94,8 +93,8 @@
      */
     public static final class Final extends PartialEscapeClosure<PartialEscapeBlockState.Final> {
 
-        public Final(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
-            super(schedule, metaAccess, constantReflection, assumptions);
+        public Final(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+            super(schedule, metaAccess, constantReflection);
         }
 
         @Override
@@ -109,10 +108,10 @@
         }
     }
 
-    public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Assumptions assumptions) {
+    public PartialEscapeClosure(SchedulePhase schedule, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
         super(schedule, schedule.getCFG());
         this.usages = schedule.getCFG().graph.createNodeBitMap();
-        this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, assumptions, this);
+        this.tool = new VirtualizerToolImpl(metaAccess, constantReflection, this);
     }
 
     /**
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Thu Feb 12 20:47:20 2015 +0100
@@ -89,9 +89,9 @@
     protected Closure<?> createEffectsClosure(PhaseContext context, SchedulePhase schedule, ControlFlowGraph cfg) {
         assert schedule != null;
         if (readElimination) {
-            return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection(), context.getAssumptions());
+            return new PEReadEliminationClosure(schedule, context.getMetaAccess(), context.getConstantReflection());
         } else {
-            return new PartialEscapeClosure.Final(schedule, context.getMetaAccess(), context.getConstantReflection(), context.getAssumptions());
+            return new PartialEscapeClosure.Final(schedule, context.getMetaAccess(), context.getConstantReflection());
         }
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -26,7 +26,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -41,13 +40,11 @@
 
     private final MetaAccessProvider metaAccess;
     private final ConstantReflectionProvider constantReflection;
-    private final Assumptions assumptions;
     private final PartialEscapeClosure<?> closure;
 
-    VirtualizerToolImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Assumptions assumptions, PartialEscapeClosure<?> closure) {
+    VirtualizerToolImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, PartialEscapeClosure<?> closure) {
         this.metaAccess = metaAccess;
         this.constantReflection = constantReflection;
-        this.assumptions = assumptions;
         this.closure = closure;
     }
 
@@ -66,11 +63,6 @@
         return constantReflection;
     }
 
-    @Override
-    public Assumptions getAssumptions() {
-        return assumptions;
-    }
-
     public void reset(PartialEscapeBlockState<?> newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) {
         deleted = false;
         state = newState;
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Thu Feb 12 20:47:20 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 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CodeFormatTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/InsertBeforeTest.java	Thu Feb 12 20:47:20 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 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ShortCircuitTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Thu Feb 12 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Implies.java	Thu Feb 12 20:47:20 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 20:46:56 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 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeAssumptions.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java	Thu Feb 12 20:47:20 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.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Thu Feb 12 20:47:20 2015 +0100
@@ -318,11 +318,11 @@
 
         // Use the "lite-probing" option, limited to a single pass of
         // probing and a single Instrument at each probed node. This
-        // particular test uses a shared event receiver at every
+        // particular test uses a shared event listener at every
         // lite-probed node.
-        final TestEventReceiver receiver = new TestEventReceiver();
+        final TestEventListener listener = new TestEventListener();
 
-        TestASTLiteProber astLiteProber = new TestASTLiteProber(receiver);
+        TestASTLiteProber astLiteProber = new TestASTLiteProber(listener);
         Probe.registerASTProber(astLiteProber);
 
         // Create a simple addition AST
@@ -337,9 +337,9 @@
         final CallTarget callTarget = runtime.createCallTarget(rootNode);
 
         // Check that the instrument is working as expected.
-        assertEquals(0, receiver.counter);
+        assertEquals(0, listener.counter);
         callTarget.call();
-        assertEquals(2, receiver.counter);
+        assertEquals(2, listener.counter);
 
         // Check that you can't probe a node that's already received a probeLite() call
         try {
@@ -409,7 +409,7 @@
         }
 
         // Use reflection to check that each WrapperNode has a ProbeLiteNode with a
-        // SimpleEventReceiver
+        // SimpleEventListener
         try {
             java.lang.reflect.Field probeNodeField = leftWrapper.getClass().getDeclaredField("probeNode");
 
@@ -420,15 +420,15 @@
             // hack: Since ProbeLiteNode is not visible, we do a string compare here
             assertTrue(probeNode.getClass().toString().endsWith("ProbeLiteNode"));
 
-            // Now we do the same to check the type of the eventReceiver in ProbeLiteNode
-            java.lang.reflect.Field eventReceiverField = probeNode.getClass().getDeclaredField("eventReceiver");
-            eventReceiverField.setAccessible(true);
-            TruffleEventReceiver eventReceiver = (TruffleEventReceiver) eventReceiverField.get(probeNode);
-            assertTrue(eventReceiver instanceof SimpleEventReceiver);
+            // Now we do the same to check the type of the eventListener in ProbeLiteNode
+            java.lang.reflect.Field eventListenerField = probeNode.getClass().getDeclaredField("eventListener");
+            eventListenerField.setAccessible(true);
+            TruffleEventListener eventListener = (TruffleEventListener) eventListenerField.get(probeNode);
+            assertTrue(eventListener instanceof SimpleEventListener);
 
             // Reset accessibility
             probeNodeField.setAccessible(false);
-            eventReceiverField.setAccessible(false);
+            eventListenerField.setAccessible(false);
 
         } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
             fail();
@@ -588,7 +588,7 @@
         public final Instrument instrument;
 
         public TestCounter() {
-            instrument = Instrument.create(new SimpleEventReceiver() {
+            instrument = Instrument.create(new SimpleEventListener() {
 
                 @Override
                 public void enter(Node node, VirtualFrame frame) {
@@ -641,19 +641,19 @@
     }
 
     /**
-     * "lite-probes" every value node with a shared event receiver.
+     * "lite-probes" every value node with a shared event listener.
      */
     private static final class TestASTLiteProber implements NodeVisitor, ASTProber {
-        private final TruffleEventReceiver eventReceiver;
+        private final TruffleEventListener eventListener;
 
-        public TestASTLiteProber(SimpleEventReceiver simpleEventReceiver) {
-            this.eventReceiver = simpleEventReceiver;
+        public TestASTLiteProber(SimpleEventListener simpleEventListener) {
+            this.eventListener = simpleEventListener;
         }
 
         public boolean visit(Node node) {
             if (node instanceof TestValueNode) {
                 final TestLanguageNode testNode = (TestValueNode) node;
-                testNode.probeLite(eventReceiver);
+                testNode.probeLite(eventListener);
             }
             return true;
         }
@@ -667,7 +667,7 @@
      * Counts the number of "enter" events at probed nodes.
      *
      */
-    static final class TestEventReceiver extends SimpleEventReceiver {
+    static final class TestEventListener extends SimpleEventListener {
 
         public int counter = 0;
 
@@ -692,7 +692,7 @@
             // where we want to count executions.
             // it will get copied when ASTs cloned, so
             // keep the count in this outer class.
-            probe.attach(Instrument.create(new SimpleEventReceiver() {
+            probe.attach(Instrument.create(new SimpleEventListener() {
 
                 @Override
                 public void enter(Node node, VirtualFrame frame) {
--- a/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Thu Feb 12 20:47:20 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/CompilerDirectives.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Thu Feb 12 20:47:20 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,11 +25,8 @@
 package com.oracle.truffle.api;
 
 import java.lang.annotation.*;
-import java.lang.reflect.*;
 import java.util.concurrent.*;
 
-import sun.misc.*;
-
 /**
  * Directives that influence the optimizations of the Truffle compiler. All of the operations have
  * no effect when executed in the Truffle interpreter.
@@ -42,22 +39,6 @@
     public static final double SLOWPATH_PROBABILITY = 0.0001;
     public static final double FASTPATH_PROBABILITY = 1.0 - SLOWPATH_PROBABILITY;
 
-    private static final Unsafe UNSAFE = getUnsafe();
-
-    private static Unsafe getUnsafe() {
-        try {
-            return Unsafe.getUnsafe();
-        } catch (SecurityException e) {
-        }
-        try {
-            Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
-            theUnsafeInstance.setAccessible(true);
-            return (Unsafe) theUnsafeInstance.get(Unsafe.class);
-        } catch (Exception e) {
-            throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
-        }
-    }
-
     /**
      * Directive for the compiler to discontinue compilation at this code position and instead
      * insert a transfer to the interpreter.
@@ -203,464 +184,6 @@
     }
 
     /**
-     * Casts the given value to the value of the given type without any checks. The class must
-     * evaluate to a constant. The condition parameter gives a hint to the compiler under which
-     * circumstances this cast can be moved to an earlier location in the program.
-     *
-     * @param value the value that is known to have the specified type
-     * @param type the specified new type of the value
-     * @param condition the condition that makes this cast safe also at an earlier location of the
-     *            program
-     * @return the value to be casted to the new type
-     */
-    @Deprecated
-    public static <T> T unsafeCast(Object value, Class<T> type, boolean condition) {
-        return unsafeCast(value, type, condition, false);
-    }
-
-    /**
-     * Casts the given value to the value of the given type without any checks. The class must
-     * evaluate to a constant. The condition parameter gives a hint to the compiler under which
-     * circumstances this cast can be moved to an earlier location in the program.
-     *
-     * @param value the value that is known to have the specified type
-     * @param type the specified new type of the value
-     * @param condition the condition that makes this cast safe also at an earlier location of the
-     *            program
-     * @param nonNull whether value is known to never be null
-     * @return the value to be casted to the new type
-     */
-    @Deprecated
-    @SuppressWarnings("unchecked")
-    public static <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull) {
-        return (T) value;
-    }
-
-    /**
-     * Unsafe access to a boolean value within an object. The condition parameter gives a hint to
-     * the compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static boolean unsafeGetBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getBoolean(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a byte value within an object. The condition parameter gives a hint to the
-     * compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static byte unsafeGetByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getByte(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a short value within an object. The condition parameter gives a hint to the
-     * compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static short unsafeGetShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getShort(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to an int value within an object. The condition parameter gives a hint to the
-     * compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getInt(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a long value within an object. The condition parameter gives a hint to the
-     * compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getLong(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a float value within an object. The condition parameter gives a hint to the
-     * compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getFloat(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a double value within an object. The condition parameter gives a hint to the
-     * compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getDouble(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to an Object value within an object. The condition parameter gives a hint to
-     * the compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getObject(receiver, offset);
-    }
-
-    /**
-     * Write a boolean value within an object. The location identity gives a hint to the compiler
-     * for improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutBoolean(Object receiver, long offset, boolean value, Object locationIdentity) {
-        UNSAFE.putBoolean(receiver, offset, value);
-    }
-
-    /**
-     * Write a byte value within an object. The location identity gives a hint to the compiler for
-     * improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutByte(Object receiver, long offset, byte value, Object locationIdentity) {
-        UNSAFE.putByte(receiver, offset, value);
-    }
-
-    /**
-     * Write a short value within an object. The location identity gives a hint to the compiler for
-     * improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutShort(Object receiver, long offset, short value, Object locationIdentity) {
-        UNSAFE.putShort(receiver, offset, value);
-    }
-
-    /**
-     * Write an int value within an object. The location identity gives a hint to the compiler for
-     * improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity) {
-        UNSAFE.putInt(receiver, offset, value);
-    }
-
-    /**
-     * Write a long value within an object. The location identity gives a hint to the compiler for
-     * improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) {
-        UNSAFE.putLong(receiver, offset, value);
-    }
-
-    /**
-     * Write a float value within an object. The location identity gives a hint to the compiler for
-     * improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity) {
-        UNSAFE.putFloat(receiver, offset, value);
-    }
-
-    /**
-     * Write a double value within an object. The location identity gives a hint to the compiler for
-     * improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity) {
-        UNSAFE.putDouble(receiver, offset, value);
-    }
-
-    /**
-     * Write an Object value within an object. The location identity gives a hint to the compiler
-     * for improved global value numbering.
-     *
-     * @param receiver the object that is written to
-     * @param offset the offset at which to write to the object in bytes
-     * @param value the value to be written
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     */
-    @Deprecated
-    public static void unsafePutObject(Object receiver, long offset, Object value, Object locationIdentity) {
-        UNSAFE.putObject(receiver, offset, value);
-    }
-
-    /**
-     * Unsafe access to a final boolean value within an object. The condition parameter gives a hint
-     * to the compiler under which circumstances this access can be moved to an earlier location in
-     * the program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static boolean unsafeGetFinalBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getBoolean(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final byte value within an object. The condition parameter gives a hint to
-     * the compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static byte unsafeGetFinalByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getByte(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final short value within an object. The condition parameter gives a hint
-     * to the compiler under which circumstances this access can be moved to an earlier location in
-     * the program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static short unsafeGetFinalShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getShort(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final int value within an object. The condition parameter gives a hint to
-     * the compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static int unsafeGetFinalInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getInt(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final long value within an object. The condition parameter gives a hint to
-     * the compiler under which circumstances this access can be moved to an earlier location in the
-     * program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static long unsafeGetFinalLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getLong(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final float value within an object. The condition parameter gives a hint
-     * to the compiler under which circumstances this access can be moved to an earlier location in
-     * the program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static float unsafeGetFinalFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getFloat(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final double value within an object. The condition parameter gives a hint
-     * to the compiler under which circumstances this access can be moved to an earlier location in
-     * the program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static double unsafeGetFinalDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getDouble(receiver, offset);
-    }
-
-    /**
-     * Unsafe access to a final Object value within an object. The condition parameter gives a hint
-     * to the compiler under which circumstances this access can be moved to an earlier location in
-     * the program. The location identity gives a hint to the compiler for improved global value
-     * numbering.
-     *
-     * @param receiver the object that is accessed
-     * @param offset the offset at which to access the object in bytes
-     * @param condition the condition that makes this access safe also at an earlier location in the
-     *            program
-     * @param locationIdentity the location identity token that can be used for improved global
-     *            value numbering or null
-     * @return the accessed value
-     */
-    @Deprecated
-    public static Object unsafeGetFinalObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
-        return UNSAFE.getObject(receiver, offset);
-    }
-
-    /**
      * Marks a method that it is considered as a boundary for Truffle partial evaluation.
      */
     @Retention(RetentionPolicy.RUNTIME)
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Thu Feb 12 20:47:20 2015 +0100
@@ -29,6 +29,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.unsafe.*;
 
 /**
  * Default implementation of the Truffle runtime if the virtual machine does not provide a better
@@ -147,6 +148,9 @@
     }
 
     public <T> T getCapability(Class<T> capability) {
+        if (capability == UnsafeAccessFactory.class) {
+            return capability.cast(new UnsafeAccessFactoryImpl());
+        }
         return null;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/UnsafeAccessFactoryImpl.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.impl;
+
+import sun.misc.*;
+
+import com.oracle.truffle.api.unsafe.*;
+
+final class UnsafeAccessFactoryImpl implements UnsafeAccessFactory {
+    public UnsafeAccess createUnsafeAccess(final Unsafe unsafe) {
+        return new UnsafeAccessImpl(unsafe);
+    }
+
+    private static final class UnsafeAccessImpl implements UnsafeAccess {
+        private final Unsafe unsafe;
+
+        private UnsafeAccessImpl(Unsafe unsafe) {
+            this.unsafe = unsafe;
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T uncheckedCast(Object value, Class<T> type, boolean condition, boolean nonNull) {
+            return (T) value;
+        }
+
+        public void putShort(Object receiver, long offset, short value, Object locationIdentity) {
+            unsafe.putShort(receiver, offset, value);
+        }
+
+        public void putObject(Object receiver, long offset, Object value, Object locationIdentity) {
+            unsafe.putObject(receiver, offset, value);
+        }
+
+        public void putLong(Object receiver, long offset, long value, Object locationIdentity) {
+            unsafe.putLong(receiver, offset, value);
+        }
+
+        public void putInt(Object receiver, long offset, int value, Object locationIdentity) {
+            unsafe.putInt(receiver, offset, value);
+        }
+
+        public void putFloat(Object receiver, long offset, float value, Object locationIdentity) {
+            unsafe.putFloat(receiver, offset, value);
+        }
+
+        public void putDouble(Object receiver, long offset, double value, Object locationIdentity) {
+            unsafe.putDouble(receiver, offset, value);
+        }
+
+        public void putByte(Object receiver, long offset, byte value, Object locationIdentity) {
+            unsafe.putByte(receiver, offset, value);
+        }
+
+        public void putBoolean(Object receiver, long offset, boolean value, Object locationIdentity) {
+            unsafe.putBoolean(receiver, offset, value);
+        }
+
+        public short getShort(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getShort(receiver, offset);
+        }
+
+        public Object getObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getObject(receiver, offset);
+        }
+
+        public long getLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getLong(receiver, offset);
+        }
+
+        public int getInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getInt(receiver, offset);
+        }
+
+        public float getFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getFloat(receiver, offset);
+        }
+
+        public double getDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getDouble(receiver, offset);
+        }
+
+        public byte getByte(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getByte(receiver, offset);
+        }
+
+        public boolean getBoolean(Object receiver, long offset, boolean condition, Object locationIdentity) {
+            return unsafe.getBoolean(receiver, offset);
+        }
+    }
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Thu Feb 12 20:47:20 2015 +0100
@@ -33,37 +33,37 @@
 // TODO (mlvdv) migrate some of this to external documentation.
 /**
  * A dynamically added/removed binding between a {@link Probe}, which provides notification of
- * {@linkplain TruffleEventReceiver execution events} taking place at a {@link Node} in a Guest
- * Language (GL) Truffle AST, and a {@linkplain TruffleEventReceiver receiver}, which consumes
+ * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest
+ * Language (GL) Truffle AST, and a {@linkplain TruffleEventListener listener}, which consumes
  * notifications on behalf of an external tool.
  * <p>
  * <h4>Summary: How to "instrument" an AST location:</h4>
  * <ol>
- * <li>Create an implementation of {@link TruffleEventReceiver} that responds to events on behalf of
+ * <li>Create an implementation of {@link TruffleEventListener} that responds to events on behalf of
  * a tool.</li>
- * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventReceiver)}.</li>
+ * <li>Create an Instrument via factory method {@link Instrument#create(TruffleEventListener)}.</li>
  * <li>"Attach" the Instrument to a Probe via {@link Probe#attach(Instrument)}, at which point event
- * notifications begin to arrive at the receiver.</li>
+ * notifications begin to arrive at the listener.</li>
  * <li>When no longer needed, "detach" the Instrument via {@link Instrument#dispose()}, at which
- * point event notifications to the receiver cease, and the Instrument becomes unusable.</li>
+ * point event notifications to the listener cease, and the Instrument becomes unusable.</li>
  * </ol>
  * <p>
- * <h4>Options for creating receivers:</h4>
+ * <h4>Options for creating listeners:</h4>
  * <p>
  * <ol>
- * <li>Implement the interface {@link TruffleEventReceiver}. The event handling methods account for
+ * <li>Implement the interface {@link TruffleEventListener}. The event handling methods account for
  * both the entry into an AST node (about to call) and several possible kinds of exit from an AST
  * node (just returned).</li>
- * <li>Extend {@link DefaultEventReceiver}, which provides a no-op implementation of every
- * {@link TruffleEventReceiver} method; override the methods of interest.</li>
- * <li>Extend {@link SimpleEventReceiver}, where return values are ignored so only two methods (for
+ * <li>Extend {@link DefaultEventListener}, which provides a no-op implementation of every
+ * {@link TruffleEventListener} method; override the methods of interest.</li>
+ * <li>Extend {@link SimpleEventListener}, where return values are ignored so only two methods (for
  * "enter" and "return") will notify all events.</li>
  * </ol>
  * <p>
- * <h4>General guidelines for receiver implementation:</h4>
+ * <h4>General guidelines for listener implementation:</h4>
  * <p>
- * When an Instrument is attached to a Probe, the receiver effectively becomes part of the executing
- * GL program; performance can be affected by the receiver's implementation.
+ * When an Instrument is attached to a Probe, the listener effectively becomes part of the executing
+ * GL program; performance can be affected by the listener's implementation.
  * <ul>
  * <li>Do not store {@link Frame} or {@link Node} references in fields.</li>
  * <li>Prefer {@code final} fields and (where performance is important) short methods.</li>
@@ -71,7 +71,7 @@
  * possible through code that is expected to be inlined, since this incurs no runtime overhead. When
  * access to frame data is needed, substitute a more expensive {@linkplain Frame#materialize()
  * materialized} representation of the frame.</li>
- * <li>If a receiver calls back to its tool during event handling, and if performance is an issue,
+ * <li>If a listener calls back to its tool during event handling, and if performance is an issue,
  * then this should be through a final "callback" field in the instrument, and the called methods
  * should be minimal.</li>
  * <li>On the other hand, implementations should prevent Truffle from inlining beyond a reasonable
@@ -85,14 +85,14 @@
  * <p>
  * <h4>Allowing for AST cloning:</h4>
  * <p>
- * Truffle routinely <em>clones</em> ASTs, which has consequences for receiver implementation.
+ * Truffle routinely <em>clones</em> ASTs, which has consequences for listener implementation.
  * <ul>
  * <li>Even though a {@link Probe} is uniquely associated with a particular location in the
  * executing Guest Language program, execution events at that location will in general be
  * implemented by different {@link Node} instances, i.e. <em>clones</em> of the originally probed
  * node.</li>
  * <li>Because of <em>cloning</em> the {@link Node} supplied with notifications to a particular
- * receiver will vary, but because they all represent the same GL program location the events should
+ * listener will vary, but because they all represent the same GL program location the events should
  * be treated as equivalent for most purposes.</li>
  * </ul>
  * <p>
@@ -107,8 +107,8 @@
  * </ul>
  * <li>Some global information is available, for example the execution
  * {@linkplain TruffleRuntime#iterateFrames(FrameInstanceVisitor) stack}.</li>
- * <li>Additional information needed by a receiver could be stored when created, preferably
- * {@code final} of course. For example, a reference to the {@link Probe} to which the receiver's
+ * <li>Additional information needed by a listener could be stored when created, preferably
+ * {@code final} of course. For example, a reference to the {@link Probe} to which the listener's
  * Instrument has been attached would give access to its corresponding
  * {@linkplain Probe#getProbedSourceSection() source location} or to the collection of
  * {@linkplain SyntaxTag tags} currently applied to the Probe.</li>
@@ -129,43 +129,43 @@
  * which can trigger deoptimization.</li>
  * </ul>
  * <p>
- * <h4>Sharing receivers:</h4>
+ * <h4>Sharing listeners:</h4>
  * <p>
- * Although an Instrument may only be attached to a single Probe, a receiver can be shared among
+ * Although an Instrument may only be attached to a single Probe, a listener can be shared among
  * multiple Instruments. This can be useful for observing events that might happen at different
  * locations in a single AST, for example all assignments to a particular variable. In this case a
  * new Instrument would be created and attached at each assignment node, but all the Instruments
- * would be created with the same receiver.
+ * would be created with the same listener.
  * <p>
  * <strong>Disclaimer:</strong> experimental; under development.
  *
  * @see Probe
- * @see TruffleEventReceiver
+ * @see TruffleEventListener
  */
 public final class Instrument {
 
     /**
-     * Creates an instrument that will route execution events to a receiver.
+     * Creates an instrument that will route execution events to a listener.
      *
-     * @param receiver a receiver for event generated by the instrument
+     * @param listener a listener for event generated by the instrument
      * @param instrumentInfo optional description of the instrument's role
      * @return a new instrument, ready for attachment at a probe
      */
-    public static Instrument create(TruffleEventReceiver receiver, String instrumentInfo) {
-        return new Instrument(receiver, instrumentInfo);
+    public static Instrument create(TruffleEventListener listener, String instrumentInfo) {
+        return new Instrument(listener, instrumentInfo);
     }
 
     /**
-     * Creates an instrument that will route execution events to a receiver.
+     * Creates an instrument that will route execution events to a listener.
      */
-    public static Instrument create(TruffleEventReceiver receiver) {
-        return new Instrument(receiver, null);
+    public static Instrument create(TruffleEventListener listener) {
+        return new Instrument(listener, null);
     }
 
     /**
-     * Tool-supplied receiver of events.
+     * Tool-supplied listener for events.
      */
-    private final TruffleEventReceiver toolEventreceiver;
+    private final TruffleEventListener toolEventListener;
 
     /**
      * Optional documentation, mainly for debugging.
@@ -179,8 +179,8 @@
 
     private Probe probe = null;
 
-    private Instrument(TruffleEventReceiver receiver, String instrumentInfo) {
-        this.toolEventreceiver = receiver;
+    private Instrument(TruffleEventListener listener, String instrumentInfo) {
+        this.toolEventListener = listener;
         this.instrumentInfo = instrumentInfo;
     }
 
@@ -240,7 +240,7 @@
     }
 
     @NodeInfo(cost = NodeCost.NONE)
-    final class InstrumentNode extends Node implements TruffleEventReceiver, InstrumentationNode {
+    final class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
 
         @Child private InstrumentNode nextInstrument;
 
@@ -287,28 +287,28 @@
         }
 
         public void enter(Node node, VirtualFrame frame) {
-            Instrument.this.toolEventreceiver.enter(node, frame);
+            Instrument.this.toolEventListener.enter(node, frame);
             if (nextInstrument != null) {
                 nextInstrument.enter(node, frame);
             }
         }
 
         public void returnVoid(Node node, VirtualFrame frame) {
-            Instrument.this.toolEventreceiver.returnVoid(node, frame);
+            Instrument.this.toolEventListener.returnVoid(node, frame);
             if (nextInstrument != null) {
                 nextInstrument.returnVoid(node, frame);
             }
         }
 
         public void returnValue(Node node, VirtualFrame frame, Object result) {
-            Instrument.this.toolEventreceiver.returnValue(node, frame, result);
+            Instrument.this.toolEventListener.returnValue(node, frame, result);
             if (nextInstrument != null) {
                 nextInstrument.returnValue(node, frame, result);
             }
         }
 
         public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
-            Instrument.this.toolEventreceiver.returnExceptional(node, frame, exception);
+            Instrument.this.toolEventListener.returnExceptional(node, frame, exception);
             if (nextInstrument != null) {
                 nextInstrument.returnExceptional(node, frame, exception);
             }
@@ -318,7 +318,7 @@
             if (Instrument.this.instrumentInfo != null) {
                 return Instrument.this.instrumentInfo;
             }
-            return toolEventreceiver.getClass().getSimpleName();
+            return toolEventListener.getClass().getSimpleName();
         }
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Thu Feb 12 20:47:20 2015 +0100
@@ -40,7 +40,7 @@
  * is intended to persist at the location, even if the specific node instance is
  * {@linkplain Node#replace(Node) replaced}.
  * <p>
- * The effect of a binding is to intercept {@linkplain TruffleEventReceiver execution events}
+ * The effect of a binding is to intercept {@linkplain TruffleEventListener execution events}
  * arriving at the node and notify each attached {@link Instrument} before execution is allowed to
  * proceed to the child.
  * <p>
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Thu Feb 12 20:47:20 2015 +0100
@@ -35,7 +35,7 @@
 /**
  * Implementation interfaces and classes for attaching {@link Probe}s to {@link WrapperNode}s.
  */
-public abstract class ProbeNode extends Node implements TruffleEventReceiver, InstrumentationNode {
+public abstract class ProbeNode extends Node implements TruffleEventListener, InstrumentationNode {
 
     /**
      * A node that can be inserted into a Truffle AST, and which enables {@linkplain Instrument
@@ -85,14 +85,14 @@
 
         /**
          * Gets the node being "wrapped", i.e. the AST node for which
-         * {@linkplain TruffleEventReceiver execution events} will be reported through the
+         * {@linkplain TruffleEventListener execution events} will be reported through the
          * Instrumentation Framework.
          */
         Node getChild();
 
         /**
          * Gets the {@link Probe} responsible for installing this wrapper; none if the wrapper
-         * installed via {@linkplain Node#probeLite(TruffleEventReceiver) "lite-Probing"}.
+         * installed via {@linkplain Node#probeLite(TruffleEventListener) "lite-Probing"}.
          */
         Probe getProbe();
 
@@ -120,8 +120,8 @@
      * Creates a new {@link ProbeLiteNode} associated with, and attached to, a Guest Language
      * specific instance of {@link WrapperNode}.
      */
-    public static void insertProbeLite(WrapperNode wrapper, TruffleEventReceiver eventReceiver) {
-        final ProbeLiteNode probeLiteNode = new ProbeLiteNode(eventReceiver);
+    public static void insertProbeLite(WrapperNode wrapper, TruffleEventListener eventListener) {
+        final ProbeLiteNode probeLiteNode = new ProbeLiteNode(eventListener);
         wrapper.insertProbe(probeLiteNode);
     }
 
@@ -277,15 +277,15 @@
     /**
      * Implementation of a probe that only ever has a single "instrument" associated with it. No
      * {@link Instrument} is ever created; instead this method simply delegates the various enter
-     * and return events to a {@link TruffleEventReceiver} passed in during construction.
+     * and return events to a {@link TruffleEventListener} passed in during construction.
      */
     @NodeInfo(cost = NodeCost.NONE)
     private static final class ProbeLiteNode extends ProbeNode {
 
-        private final TruffleEventReceiver eventReceiver;
+        private final TruffleEventListener eventListener;
 
-        private ProbeLiteNode(TruffleEventReceiver eventReceiver) {
-            this.eventReceiver = eventReceiver;
+        private ProbeLiteNode(TruffleEventListener eventListener) {
+            this.eventListener = eventListener;
         }
 
         @Override
@@ -306,19 +306,19 @@
         }
 
         public void enter(Node node, VirtualFrame frame) {
-            eventReceiver.enter(node, frame);
+            eventListener.enter(node, frame);
         }
 
         public void returnVoid(Node node, VirtualFrame frame) {
-            eventReceiver.returnVoid(node, frame);
+            eventListener.returnVoid(node, frame);
         }
 
         public void returnValue(Node node, VirtualFrame frame, Object result) {
-            eventReceiver.returnValue(node, frame, result);
+            eventListener.returnValue(node, frame, result);
         }
 
         public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
-            eventReceiver.returnExceptional(node, frame, exception);
+            eventListener.returnExceptional(node, frame, exception);
         }
 
         public String instrumentationInfo() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.instrument;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A listener of Truffle AST runtime execution events that can collect information and possibly
+ * intervene on behalf of an external tool.
+ */
+public interface TruffleEventListener {
+
+    /**
+     * Receive notification that an AST node's execute method is about to be called.
+     */
+    void enter(Node node, VirtualFrame frame);
+
+    /**
+     * Receive notification that an AST Node's {@code void}-valued execute method has just returned.
+     */
+    void returnVoid(Node node, VirtualFrame frame);
+
+    /**
+     * Receive notification that an AST Node'sexecute method has just returned a value (boxed if
+     * primitive).
+     */
+    void returnValue(Node node, VirtualFrame frame, Object result);
+
+    /**
+     * Receive notification that an AST Node's execute method has just thrown an exception.
+     */
+    void returnExceptional(Node node, VirtualFrame frame, Exception exception);
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventReceiver.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  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.instrument;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A receiver of Truffle AST runtime execution events that can collect information and possibly
- * intervene on behalf of an external tool.
- */
-public interface TruffleEventReceiver {
-
-    /**
-     * Receive notification that an AST node's execute method is about to be called.
-     */
-    void enter(Node node, VirtualFrame frame);
-
-    /**
-     * Receive notification that an AST Node's {@code void}-valued execute method has just returned.
-     */
-    void returnVoid(Node node, VirtualFrame frame);
-
-    /**
-     * Receive notification that an AST Node'sexecute method has just returned a value (boxed if
-     * primitive).
-     */
-    void returnValue(Node node, VirtualFrame frame, Object result);
-
-    /**
-     * Receive notification that an AST Node's execute method has just thrown an exception.
-     */
-    void returnExceptional(Node node, VirtualFrame frame, Exception exception);
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, 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.instrument.impl;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * A listener for AST {@linkplain TruffleEventListener execution events} that provides a no-op
+ * implementation of every event.
+ */
+public class DefaultEventListener implements TruffleEventListener {
+
+    public void enter(Node node, VirtualFrame frame) {
+    }
+
+    public void returnVoid(Node node, VirtualFrame frame) {
+    }
+
+    public void returnValue(Node node, VirtualFrame frame, Object result) {
+    }
+
+    public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventReceiver.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +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.  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.instrument.impl;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * A receiver for AST {@linkplain TruffleEventReceiver execution events} that provides a no-op
- * implementation of every event.
- */
-public class DefaultEventReceiver implements TruffleEventReceiver {
-
-    public void enter(Node node, VirtualFrame frame) {
-    }
-
-    public void returnVoid(Node node, VirtualFrame frame) {
-    }
-
-    public void returnValue(Node node, VirtualFrame frame, Object result) {
-    }
-
-    public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014, 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.instrument.impl;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * An abstract listener for AST {@linkplain TruffleEventListener execution events} that ignores
+ * return values and supports handling all events by overriding only two methods:
+ * <ul>
+ * <li>{@link #enter(Node, VirtualFrame)}, and</li>
+ * <li>{@link #returnAny(Node, VirtualFrame)}.</li>
+ * </ul>
+ */
+public abstract class SimpleEventListener implements TruffleEventListener {
+
+    public void enter(Node node, VirtualFrame frame) {
+    }
+
+    /**
+     * Receive notification that one of an AST Node's execute methods has just returned by any
+     * means: with or without a return value (ignored) or via exception (ignored).
+     *
+     * @param node
+     * @param frame
+     */
+    public void returnAny(Node node, VirtualFrame frame) {
+    }
+
+    public final void returnVoid(Node node, VirtualFrame frame) {
+        returnAny(node, frame);
+    }
+
+    public final void returnValue(Node node, VirtualFrame frame, Object result) {
+        returnAny(node, frame);
+    }
+
+    public final void returnExceptional(Node node, VirtualFrame frame, Exception e) {
+        returnAny(node, frame);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventReceiver.java	Thu Feb 12 20:46:56 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.  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.instrument.impl;
-
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.instrument.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * An abstract receiver for AST {@linkplain TruffleEventReceiver execution events} that ignores
- * return values and supports handling all events by overriding only two methods:
- * <ul>
- * <li>{@link #enter(Node, VirtualFrame)}, and</li>
- * <li>{@link #returnAny(Node, VirtualFrame)}.</li>
- * </ul>
- */
-public abstract class SimpleEventReceiver implements TruffleEventReceiver {
-
-    public void enter(Node node, VirtualFrame frame) {
-    }
-
-    /**
-     * Receive notification that one of an AST Node's execute methods has just returned by any
-     * means: with or without a return value (ignored) or via exception (ignored).
-     *
-     * @param node
-     * @param frame
-     */
-    public void returnAny(Node node, VirtualFrame frame) {
-    }
-
-    public final void returnVoid(Node node, VirtualFrame frame) {
-        returnAny(node, frame);
-    }
-
-    public final void returnValue(Node node, VirtualFrame frame, Object result) {
-        returnAny(node, frame);
-    }
-
-    public final void returnExceptional(Node node, VirtualFrame frame, Exception e) {
-        returnAny(node, frame);
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java	Thu Feb 12 20:47:20 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.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Thu Feb 12 20:47:20 2015 +0100
@@ -504,16 +504,16 @@
      * its parent; the wrapper node must be provided by implementations of
      * {@link #createWrapperNode()}.
      * <p>
-     * Unlike {@link #probe()}, once {@link #probeLite(TruffleEventReceiver)} is called at a node,
+     * Unlike {@link #probe()}, once {@link #probeLite(TruffleEventListener)} is called at a node,
      * no additional probing can be added and no additional instrumentation can be attached.
      * <p>
      * This restricted form of instrumentation is intended for special cases where only one kind of
      * instrumentation is desired, and for which performance is a concern
      *
-     * @param eventReceiver
+     * @param eventListener
      * @throws ProbeException (unchecked) when a probe cannot be created, leaving the AST unchanged
      */
-    public final void probeLite(TruffleEventReceiver eventReceiver) {
+    public final void probeLite(TruffleEventListener eventListener) {
 
         if (this instanceof WrapperNode) {
             throw new ProbeException(ProbeFailure.Reason.WRAPPER_NODE, null, this, null);
@@ -545,7 +545,7 @@
         }
 
         // Connect it to a Probe
-        ProbeNode.insertProbeLite(wrapper, eventReceiver);
+        ProbeNode.insertProbeLite(wrapper, eventListener);
 
         // Replace this node in the AST with the wrapper
         this.replace(wrapperNode);
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Thu Feb 12 20:47:20 2015 +0100
@@ -29,7 +29,6 @@
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.*;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.instrument.impl.*;
@@ -52,7 +51,7 @@
  * <p>
  * <ul>
  * <li>"Execution call" on a node is is defined as invocation of a node method that is instrumented
- * to produce the event {@link TruffleEventReceiver#enter(Node, VirtualFrame)};</li>
+ * to produce the event {@link TruffleEventListener#enter(Node, VirtualFrame)};</li>
  * <li>Execution calls are tabulated only at <em>instrumented</em> nodes, i.e. those for which
  * {@linkplain Node#isInstrumentable() isInstrumentable() == true};</li>
  * <li>Execution calls are tabulated only at nodes present in the AST when originally created;
@@ -75,13 +74,13 @@
 public final class CoverageTracker extends InstrumentationTool {
 
     /** Counting data. */
-    private final Map<LineLocation, CoverageCounter> counters = new HashMap<>();
+    private final Map<LineLocation, CoverageRecord> coverageMap = new HashMap<>();
 
-    /** For disposal. */
+    /** Needed for disposal. */
     private final List<Instrument> instruments = new ArrayList<>();
 
     /**
-     * Counting is restricted to nodes holding this tag.
+     * Coverage counting is restricted to nodes holding this tag.
      */
     private final SyntaxTag countingTag;
 
@@ -112,7 +111,7 @@
 
     @Override
     protected void internalReset() {
-        counters.clear();
+        coverageMap.clear();
     }
 
     @Override
@@ -142,22 +141,21 @@
          * every line associated with an appropriately tagged AST node; iterable in order of source
          * name, then line number.
          */
-        final TreeSet<Entry<LineLocation, CoverageCounter>> entries = new TreeSet<>(new LineLocationEntryComparator());
+        final TreeSet<Entry<LineLocation, CoverageRecord>> entries = new TreeSet<>(new LineLocationEntryComparator());
 
-        final Map<Source, Long[]> results = new HashMap<>();
-
-        for (Entry<LineLocation, CoverageCounter> entry : counters.entrySet()) {
+        for (Entry<LineLocation, CoverageRecord> entry : coverageMap.entrySet()) {
             entries.add(entry);
         }
+        final Map<Source, Long[]> result = new HashMap<>();
         Source curSource = null;
         Long[] curLineTable = null;
-        for (Entry<LineLocation, CoverageCounter> entry : entries) {
+        for (Entry<LineLocation, CoverageRecord> entry : entries) {
             final LineLocation key = entry.getKey();
             final Source source = key.getSource();
             final int lineNo = key.getLineNumber();
             if (source != curSource) {
                 if (curSource != null) {
-                    results.put(curSource, curLineTable);
+                    result.put(curSource, curLineTable);
                 }
                 curSource = source;
                 curLineTable = new Long[source.getLineCount()];
@@ -165,9 +163,9 @@
             curLineTable[lineNo - 1] = entry.getValue().count.longValue();
         }
         if (curSource != null) {
-            results.put(curSource, curLineTable);
+            result.put(curSource, curLineTable);
         }
-        return results;
+        return result;
     }
 
     /**
@@ -183,14 +181,14 @@
          * every line associated with an appropriately tagged AST node; iterable in order of source
          * name, then line number.
          */
-        final TreeSet<Entry<LineLocation, CoverageCounter>> entries = new TreeSet<>(new LineLocationEntryComparator());
+        final TreeSet<Entry<LineLocation, CoverageRecord>> entries = new TreeSet<>(new LineLocationEntryComparator());
 
-        for (Entry<LineLocation, CoverageCounter> entry : counters.entrySet()) {
+        for (Entry<LineLocation, CoverageRecord> entry : coverageMap.entrySet()) {
             entries.add(entry);
         }
         Source curSource = null;
         int curLineNo = 1;
-        for (Entry<LineLocation, CoverageCounter> entry : entries) {
+        for (Entry<LineLocation, CoverageRecord> entry : entries) {
             final LineLocation key = entry.getKey();
             final Source source = key.getSource();
             final int lineNo = key.getLineNumber();
@@ -228,9 +226,9 @@
     }
 
     /**
-     * A receiver for events at each instrumented AST location. This receiver counts
-     * "execution calls" to the instrumented node and is <em>stateful</em>. State in receivers must
-     * be considered carefully since ASTs, along with all instrumentation (including event receivers
+     * A listener for events at each instrumented AST location. This listener counts
+     * "execution calls" to the instrumented node and is <em>stateful</em>. State in listeners must
+     * be considered carefully since ASTs, along with all instrumentation (including event listener
      * such as this) are routinely cloned by the Truffle runtime. AST cloning is <em>shallow</em>
      * (for non- {@link Child} nodes), so in this case the actual count <em>is shared</em> among all
      * the clones; the count is also held in a table indexed by source line.
@@ -238,7 +236,7 @@
      * In contrast, a primitive field would <em>not</em> be shared among clones and resulting counts
      * would not be accurate.
      */
-    private final class CoverageEventReceiver extends DefaultEventReceiver {
+    private final class CoverageEventListener extends DefaultEventListener {
 
         /**
          * Shared by all clones of the associated instrument and by the table of counters for the
@@ -246,12 +244,11 @@
          */
         private final AtomicLong count;
 
-        CoverageEventReceiver(AtomicLong count) {
+        CoverageEventListener(AtomicLong count) {
             this.count = count;
         }
 
         @Override
-        @TruffleBoundary
         public void enter(Node node, VirtualFrame frame) {
             if (isEnabled()) {
                 count.getAndIncrement();
@@ -259,9 +256,9 @@
         }
     }
 
-    private static final class LineLocationEntryComparator implements Comparator<Entry<LineLocation, CoverageCounter>> {
+    private static final class LineLocationEntryComparator implements Comparator<Entry<LineLocation, CoverageRecord>> {
 
-        public int compare(Entry<LineLocation, CoverageCounter> e1, Entry<LineLocation, CoverageCounter> e2) {
+        public int compare(Entry<LineLocation, CoverageRecord> e1, Entry<LineLocation, CoverageRecord> e2) {
             return LineLocation.COMPARATOR.compare(e1.getKey(), e2.getKey());
         }
     }
@@ -279,35 +276,37 @@
                 if (srcSection == null) {
                     // TODO (mlvdv) report this?
                 } else {
+                    // Get the source line where the
                     final LineLocation lineLocation = srcSection.getLineLocation();
-                    CoverageCounter counter = counters.get(lineLocation);
-                    if (counter != null) {
+                    CoverageRecord record = coverageMap.get(lineLocation);
+                    if (record != null) {
                         // Another node starts on same line; count only the first (textually)
-                        if (srcSection.getCharIndex() > counter.srcSection.getCharIndex()) {
-                            // Counter already in place, corresponds to code earlier on line
+                        if (srcSection.getCharIndex() > record.srcSection.getCharIndex()) {
+                            // Record already in place, corresponds to code earlier on line
                             return;
                         } else {
-                            // Counter already in place, corresponds to later code; replace it
-                            counter.instrument.dispose();
+                            // Record already in place, corresponds to later code; replace it
+                            record.instrument.dispose();
                         }
                     }
                     final AtomicLong count = new AtomicLong();
-                    final CoverageEventReceiver eventReceiver = new CoverageEventReceiver(count);
-                    final Instrument instrument = Instrument.create(eventReceiver, CoverageTracker.class.getSimpleName());
+                    final CoverageEventListener eventListener = new CoverageEventListener(count);
+                    final Instrument instrument = Instrument.create(eventListener, CoverageTracker.class.getSimpleName());
                     instruments.add(instrument);
                     probe.attach(instrument);
-                    counters.put(lineLocation, new CoverageCounter(srcSection, instrument, count));
+                    coverageMap.put(lineLocation, new CoverageRecord(srcSection, instrument, count));
                 }
             }
         }
     }
 
-    private class CoverageCounter {
-        final SourceSection srcSection;
-        final Instrument instrument;
+    private class CoverageRecord {
+
+        final SourceSection srcSection; // The text of the code being counted
+        final Instrument instrument;  // The attached Instrument, in case need to remove.
         final AtomicLong count;
 
-        CoverageCounter(SourceSection srcSection, Instrument instrument, AtomicLong count) {
+        CoverageRecord(SourceSection srcSection, Instrument instrument, AtomicLong count) {
             this.srcSection = srcSection;
             this.instrument = instrument;
             this.count = count;
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Thu Feb 12 20:47:20 2015 +0100
@@ -49,7 +49,7 @@
  * <p>
  * <ul>
  * <li>"Execution call" on a node is is defined as invocation of a node method that is instrumented
- * to produce the event {@link TruffleEventReceiver#enter(Node, VirtualFrame)};</li>
+ * to produce the event {@link TruffleEventListener#enter(Node, VirtualFrame)};</li>
  * <li>Execution calls are tabulated only at <em>instrumented</em> nodes, i.e. those for which
  * {@linkplain Node#isInstrumentable() isInstrumentable() == true};</li>
  * <li>Execution calls are tabulated only at nodes present in the AST when originally created;
@@ -92,26 +92,38 @@
     }
 
     /**
-     * Receiver for events at instrumented nodes. Counts are maintained in a shared table, so the
-     * receiver is stateless and can be shared by every {@link Instrument}.
+     * Listener for events at instrumented nodes. Counts are maintained in a shared table, so the
+     * listener is stateless and can be shared by every {@link Instrument}.
      */
-    private final TruffleEventReceiver eventReceiver = new DefaultEventReceiver() {
+    private final TruffleEventListener eventListener = new DefaultEventListener() {
         @Override
         public void enter(Node node, VirtualFrame frame) {
-            internalReceive(node);
+            if (isEnabled()) {
+                final Class<?> nodeClass = node.getClass();
+                /*
+                 * Everything up to here is inlined by Truffle compilation. Delegate the next part
+                 * to a method behind an inlining boundary.
+                 *
+                 * Note that it is not permitted to pass a {@link VirtualFrame} across an inlining
+                 * boundary; they are truly virtual in inlined code.
+                 */
+                AtomicLong nodeCounter = getCounter(nodeClass);
+                nodeCounter.getAndIncrement();
+            }
         }
 
+        /**
+         * Mark this method as a boundary that will stop Truffle inlining, which should not be
+         * allowed to inline the hash table method or any other complex library code.
+         */
         @TruffleBoundary
-        private void internalReceive(Node node) {
-            if (isEnabled()) {
-                final Class<?> nodeClass = node.getClass();
-                AtomicLong nodeCounter = counters.get(nodeClass);
-                if (nodeCounter == null) {
-                    nodeCounter = new AtomicLong();
-                    counters.put(nodeClass, nodeCounter);
-                }
-                nodeCounter.getAndIncrement();
+        private AtomicLong getCounter(Class<?> nodeClass) {
+            AtomicLong nodeCounter = counters.get(nodeClass);
+            if (nodeCounter == null) {
+                nodeCounter = new AtomicLong();
+                counters.put(nodeClass, nodeCounter);
             }
+            return nodeCounter;
         }
     };
 
@@ -268,7 +280,7 @@
 
             if (node.isInstrumentable()) {
                 try {
-                    final Instrument instrument = Instrument.create(eventReceiver, "NodeExecCounter");
+                    final Instrument instrument = Instrument.create(eventListener, "NodeExecCounter");
                     instruments.add(instrument);
                     node.probe().attach(instrument);
                 } catch (ProbeException ex) {
@@ -292,7 +304,7 @@
         @Override
         public void probeTaggedAs(Probe probe, SyntaxTag tag, Object tagValue) {
             if (countingTag == tag) {
-                final Instrument instrument = Instrument.create(eventReceiver, NodeExecCounter.class.getSimpleName());
+                final Instrument instrument = Instrument.create(eventListener, NodeExecCounter.class.getSimpleName());
                 instruments.add(instrument);
                 probe.attach(instrument);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/unsafe/UnsafeAccess.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.unsafe;
+
+public interface UnsafeAccess {
+
+    /**
+     * Casts the given value to the value of the given type without any checks. The class must
+     * evaluate to a constant. The condition parameter gives a hint to the compiler under which
+     * circumstances this cast can be moved to an earlier location in the program.
+     *
+     * @param value the value that is known to have the specified type
+     * @param type the specified new type of the value
+     * @param condition the condition that makes this cast safe also at an earlier location of the
+     *            program
+     * @param nonNull whether value is known to never be null
+     * @return the value to be casted to the new type
+     */
+    <T> T uncheckedCast(Object value, Class<T> type, boolean condition, boolean nonNull);
+
+    /**
+     * Unsafe access to a boolean value within an object. The condition parameter gives a hint to
+     * the compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    boolean getBoolean(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to a byte value within an object. The condition parameter gives a hint to the
+     * compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    byte getByte(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to a short value within an object. The condition parameter gives a hint to the
+     * compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    short getShort(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to an int value within an object. The condition parameter gives a hint to the
+     * compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    int getInt(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to a long value within an object. The condition parameter gives a hint to the
+     * compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    long getLong(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to a float value within an object. The condition parameter gives a hint to the
+     * compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    float getFloat(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to a double value within an object. The condition parameter gives a hint to the
+     * compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    double getDouble(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Unsafe access to an Object value within an object. The condition parameter gives a hint to
+     * the compiler under which circumstances this access can be moved to an earlier location in the
+     * program. The location identity gives a hint to the compiler for improved global value
+     * numbering.
+     *
+     * @param receiver the object that is accessed
+     * @param offset the offset at which to access the object in bytes
+     * @param condition the condition that makes this access safe also at an earlier location in the
+     *            program
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     * @return the accessed value
+     */
+    Object getObject(Object receiver, long offset, boolean condition, Object locationIdentity);
+
+    /**
+     * Write a boolean value within an object. The location identity gives a hint to the compiler
+     * for improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putBoolean(Object receiver, long offset, boolean value, Object locationIdentity);
+
+    /**
+     * Write a byte value within an object. The location identity gives a hint to the compiler for
+     * improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putByte(Object receiver, long offset, byte value, Object locationIdentity);
+
+    /**
+     * Write a short value within an object. The location identity gives a hint to the compiler for
+     * improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putShort(Object receiver, long offset, short value, Object locationIdentity);
+
+    /**
+     * Write an int value within an object. The location identity gives a hint to the compiler for
+     * improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putInt(Object receiver, long offset, int value, Object locationIdentity);
+
+    /**
+     * Write a long value within an object. The location identity gives a hint to the compiler for
+     * improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putLong(Object receiver, long offset, long value, Object locationIdentity);
+
+    /**
+     * Write a float value within an object. The location identity gives a hint to the compiler for
+     * improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putFloat(Object receiver, long offset, float value, Object locationIdentity);
+
+    /**
+     * Write a double value within an object. The location identity gives a hint to the compiler for
+     * improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putDouble(Object receiver, long offset, double value, Object locationIdentity);
+
+    /**
+     * Write an Object value within an object. The location identity gives a hint to the compiler
+     * for improved global value numbering.
+     *
+     * @param receiver the object that is written to
+     * @param offset the offset at which to write to the object in bytes
+     * @param value the value to be written
+     * @param locationIdentity the location identity token that can be used for improved global
+     *            value numbering or null
+     */
+    void putObject(Object receiver, long offset, Object value, Object locationIdentity);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/unsafe/UnsafeAccessFactory.java	Thu Feb 12 20:47:20 2015 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.unsafe;
+
+import sun.misc.*;
+
+public interface UnsafeAccessFactory {
+    UnsafeAccess createUnsafeAccess(Unsafe unsafe);
+}
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Thu Feb 12 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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);
+        resolver.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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java	Thu Feb 12 20:47:20 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 20:46:56 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Thu Feb 12 20:47:20 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 20:46:56 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 20:46:56 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Thu Feb 12 20:47:20 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) {
@@ -570,7 +569,7 @@
     public static TypeElement findNearestEnclosingType(Element element) {
         List<Element> elements = getElementHierarchy(element);
         for (Element e : elements) {
-            if (e.getKind().isClass()) {
+            if (e.getKind().isClass() || e.getKind().isInterface()) {
                 return (TypeElement) e;
             }
         }
@@ -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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeElement.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeVariableElement.java	Thu Feb 12 20:47:20 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 20:47:20 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 20:47:20 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 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Thu Feb 12 20:47:20 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 20:46:56 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Thu Feb 12 20:47:20 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 20:46:56 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ShortCircuitParser.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java	Thu Feb 12 20:47:20 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.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Thu Feb 12 20:47:20 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -218,8 +218,8 @@
 
                 // Attach an instrument to every probe tagged as an assignment
                 for (Probe probe : Probe.findProbesTaggedAs(StandardSyntaxTag.ASSIGNMENT)) {
-                    SLPrintAssigmentValueReciever slPrintAssigmentValueReceiver = new SLPrintAssigmentValueReciever(printer);
-                    probe.attach(Instrument.create(slPrintAssigmentValueReceiver, "SL print assignment value"));
+                    SLPrintAssigmentValueListener slPrintAssigmentValueListener = new SLPrintAssigmentValueListener(printer);
+                    probe.attach(Instrument.create(slPrintAssigmentValueListener, "SL print assignment value"));
                 }
 
                 SLFunction main = slContext.getFunctionRegistry().lookup("main");
@@ -271,16 +271,16 @@
     }
 
     /**
-     * This sample instrument receiver provides prints the value of an assignment (after the
+     * This sample instrument listener provides prints the value of an assignment (after the
      * assignment is complete) to the {@link PrintStream} specified in the constructor. This
      * instrument can only be attached to a wrapped {@link SLWriteLocalVariableNode}, but provides
      * no guards to protect it from being attached elsewhere.
      */
-    public final class SLPrintAssigmentValueReciever extends DefaultEventReceiver {
+    public final class SLPrintAssigmentValueListener extends DefaultEventListener {
 
         private PrintStream output;
 
-        public SLPrintAssigmentValueReciever(PrintStream output) {
+        public SLPrintAssigmentValueListener(PrintStream output) {
             this.output = output;
         }
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Thu Feb 12 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java	Thu Feb 12 20:47:20 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 20:46:56 2015 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Thu Feb 12 20:47:20 2015 +0100
@@ -204,11 +204,9 @@
   GRAAL_ONLY(do_klass(HotSpotMetaspaceConstantImpl_klass,    com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstantImpl,   Graal)) \
   GRAAL_ONLY(do_klass(HotSpotStackFrameReference_klass,      com_oracle_graal_hotspot_HotSpotStackFrameReference,          Graal)) \
   GRAAL_ONLY(do_klass(CompilationTask_klass,                 com_oracle_graal_hotspot_CompilationTask,                     Graal)) \
-  GRAAL_ONLY(do_klass(Assumptions_klass,                     com_oracle_graal_api_code_Assumptions,                        Graal)) \
   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 20:46:56 2015 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Thu Feb 12 20:47:20 2015 +0100
@@ -321,8 +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,                    "com/oracle/graal/api/code/Assumptions"))                         \
-  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/compiler/compileBroker.cpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Thu Feb 12 20:47:20 2015 +0100
@@ -1987,6 +1987,11 @@
   int compilable = ciEnv::MethodCompilable;
   AbstractCompiler *comp = compiler(task_level);
 
+  int system_dictionary_modification_counter;
+  {
+    MutexLocker locker(Compile_lock, thread);
+    system_dictionary_modification_counter = SystemDictionary::number_of_modifications();
+  }
 #ifdef COMPILERGRAAL
   if (comp != NULL && comp->is_graal()) {
     GraalCompiler* graal = (GraalCompiler*) comp;
@@ -1994,17 +1999,13 @@
     TraceTime t1("compilation", &time);
     EventCompilation event;
 
-    graal->compile_method(target_handle, osr_bci, task);
+    GraalEnv env(task, system_dictionary_modification_counter);
+    graal->compile_method(target_handle, osr_bci, &env);
 
     post_compile(thread, task, event, task->code() != NULL, NULL);
   } else
 #endif // COMPILERGRAAL
   {
-    int system_dictionary_modification_counter;
-    {
-      MutexLocker locker(Compile_lock, thread);
-      system_dictionary_modification_counter = SystemDictionary::number_of_modifications();
-    }
 
     NoHandleMark  nhm;
     ThreadToNativeFromVM ttn(thread);
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Thu Feb 12 20:47:20 2015 +0100
@@ -384,21 +384,18 @@
   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);
   _dependencies = new Dependencies(&_arena, _oop_recorder, compilerThread != NULL ? compilerThread->log() : NULL);
-  Handle assumptions_handle = CompilationResult::assumptions(HotSpotCompiledCode::comp(compiled_code));
-  if (!assumptions_handle.is_null()) {
-    objArrayHandle assumptions(Thread::current(), Assumptions::list(assumptions_handle()));
+  objArrayHandle assumptions = CompilationResult::assumptions(HotSpotCompiledCode::comp(compiled_code));
+  if (!assumptions.is_null()) {
     int length = assumptions->length();
     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);
@@ -413,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
@@ -424,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();
@@ -456,13 +462,13 @@
     methodHandle method = getMethodFromHotSpotMethod(HotSpotCompiledNmethod::method(compiled_code));
     jint entry_bci = HotSpotCompiledNmethod::entryBCI(compiled_code);
     jint id = HotSpotCompiledNmethod::id(compiled_code);
-    CompileTask* task = (CompileTask*) (address) HotSpotCompiledNmethod::ctask(compiled_code);
+    GraalEnv* env = (GraalEnv*) (address) HotSpotCompiledNmethod::graalEnv(compiled_code);
     if (id == -1) {
       // Make sure a valid compile_id is associated with every compile
       id = CompileBroker::assign_compile_id_unlocked(Thread::current(), method, entry_bci);
     }
     result = GraalEnv::register_method(method, nm, entry_bci, &_offsets, _custom_stack_area_offset, &buffer, stack_slots, _debug_recorder->_oopmaps, &_exception_handler_table,
-        GraalCompiler::instance(), _debug_recorder, _dependencies, task, id, false, installed_code, speculation_log);
+        GraalCompiler::instance(), _debug_recorder, _dependencies, env, id, false, installed_code, speculation_log);
     cb = nm;
   }
 
@@ -639,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 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Thu Feb 12 20:47:20 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/graalCompiler.cpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Thu Feb 12 20:47:20 2015 +0100
@@ -105,7 +105,7 @@
   _bootstrapping = false;
 }
 
-void GraalCompiler::compile_method(methodHandle method, int entry_bci, CompileTask* task) {
+void GraalCompiler::compile_method(methodHandle method, int entry_bci, GraalEnv* env) {
   GRAAL_EXCEPTION_CONTEXT
 
   bool is_osr = entry_bci != InvocationEntryBci;
@@ -122,8 +122,8 @@
   JavaCallArguments args;
   args.push_long((jlong) (address) method());
   args.push_int(entry_bci);
-  args.push_long((jlong) (address) task);
-  args.push_int(task->compile_id());
+  args.push_long((jlong) (address) env);
+  args.push_int(env->task()->compile_id());
   JavaCalls::call_static(&result, SystemDictionary::CompilationTask_klass(), vmSymbols::compileMetaspaceMethod_name(), vmSymbols::compileMetaspaceMethod_signature(), &args, CHECK_ABORT);
 
   _methodsCompiled++;
--- a/src/share/vm/graal/graalCompiler.hpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Thu Feb 12 20:47:20 2015 +0100
@@ -25,6 +25,7 @@
 #define SHARE_VM_GRAAL_GRAAL_COMPILER_HPP
 
 #include "compiler/abstractCompiler.hpp"
+#include "graal/graalEnv.hpp"
 
 class GraalCompiler : public AbstractCompiler {
 
@@ -72,7 +73,7 @@
   // Compilation entry point for methods
   virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci);
 
-  void compile_method(methodHandle target, int entry_bci, CompileTask* task);
+  void compile_method(methodHandle target, int entry_bci, GraalEnv* env);
 
   // Print compilation timers and statistics
   virtual void print_timers();
--- a/src/share/vm/graal/graalEnv.cpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalEnv.cpp	Thu Feb 12 20:47:20 2015 +0100
@@ -45,6 +45,18 @@
 #include "graal/graalRuntime.hpp"
 #include "graal/graalJavaAccess.hpp"
 
+GraalEnv::GraalEnv(CompileTask* task, int system_dictionary_modification_counter) {
+  _task = task;
+  _system_dictionary_modification_counter = system_dictionary_modification_counter;
+  {
+    // Get Jvmti capabilities under lock to get consistent values.
+    MutexLocker mu(JvmtiThreadState_lock);
+    _jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint();
+    _jvmti_can_access_local_variables     = JvmtiExport::can_access_local_variables();
+    _jvmti_can_post_on_exceptions         = JvmtiExport::can_post_on_exceptions();
+  }
+}
+
 // ------------------------------------------------------------------
 // Note: the logic of this method should mirror the logic of
 // constantPoolOopDesc::verify_constant_pool_resolve.
@@ -409,19 +421,23 @@
 // ------------------------------------------------------------------
 // Check for changes to the system dictionary during compilation
 // class loads, evolution, breakpoints
-bool GraalEnv::check_for_system_dictionary_modification(Dependencies* dependencies) {
-  // Dependencies must be checked when the system dictionary changes.
-  // If logging is enabled all violated dependences will be recorded in
-  // the log.  In debug mode check dependencies even if the system
-  // dictionary hasn't changed to verify that no invalid dependencies
-  // were inserted.  Any violated dependences in this case are dumped to
-  // the tty.
+bool GraalEnv::check_for_system_dictionary_modification(Dependencies* dependencies, GraalEnv* env) {
+  // If JVMTI capabilities were enabled during compile, the compilation is invalidated.
+  if (env != NULL) {
+    if (!env->_jvmti_can_hotswap_or_post_breakpoint && JvmtiExport::can_hotswap_or_post_breakpoint()) {
+      // Hotswapping or breakpointing was enabled during compilation
+      return false;
+    }
+  }
 
-  // TODO (thomaswue): Always check dependency for now.
-  //bool counter_changed = system_dictionary_modification_counter_changed();
-  //bool test_deps = counter_changed;
-  //DEBUG_ONLY(test_deps = true);
-  //if (!test_deps)  return;
+  // Dependencies must be checked when the system dictionary changes
+  // or if we don't know whether it has changed (i.e., env == NULL).
+  // In debug mode, always check dependencies.
+  bool counter_changed = env != NULL && env->_system_dictionary_modification_counter != SystemDictionary::number_of_modifications();
+  bool verify_deps = env == NULL || trueInDebug;
+  if (!counter_changed && !verify_deps) {
+    return true;
+  }
 
   for (Dependencies::DepStream deps(dependencies); deps.next(); ) {
     Klass*  witness = deps.check_dependency();
@@ -450,7 +466,7 @@
                                 AbstractCompiler* compiler,
                                 DebugInformationRecorder* debug_info,
                                 Dependencies* dependencies,
-                                CompileTask* task,
+                                GraalEnv* env,
                                 int compile_id,
                                 bool has_unsafe_access,
                                 Handle installed_code,
@@ -471,7 +487,7 @@
     dependencies->encode_content_bytes();
 
     // Check for {class loads, evolution, breakpoints} during compilation
-    if (!check_for_system_dictionary_modification(dependencies)) {
+    if (!check_for_system_dictionary_modification(dependencies, env)) {
       // While not a true deoptimization, it is a preemptive decompile.
       MethodData* mdp = method()->method_data();
       if (mdp != NULL) {
@@ -516,6 +532,7 @@
 
       // Record successful registration.
       // (Put nm into the task handle *before* publishing to the Java heap.)
+      CompileTask* task = env == NULL ? NULL : env->task();
       if (task != NULL)  task->set_code(nm);
 
       if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) {
--- a/src/share/vm/graal/graalEnv.hpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalEnv.hpp	Thu Feb 12 20:47:20 2015 +0100
@@ -50,7 +50,7 @@
 //
 // This class is the top level broker for requests from the compiler
 // to the VM.
-class GraalEnv : AllStatic {
+class GraalEnv : StackObj {
   CI_PACKAGE_ACCESS_TO
 
   friend class CompileBroker;
@@ -92,7 +92,16 @@
                                  int method_index, Bytecodes::Code bc,
                                  instanceKlassHandle& loading_klass);
 
+  GraalEnv(CompileTask* task, int system_dictionary_modification_counter);
+
 private:
+  CompileTask*     _task;
+  int              _system_dictionary_modification_counter;
+
+  // Cache JVMTI state
+  bool  _jvmti_can_hotswap_or_post_breakpoint;
+  bool  _jvmti_can_access_local_variables;
+  bool  _jvmti_can_post_on_exceptions;
 
   // Implementation methods for loading and constant pool access.
   static KlassHandle get_klass_by_name_impl(KlassHandle& accessing_klass,
@@ -124,9 +133,11 @@
 
   // Helper routine for determining the validity of a compilation
   // with respect to concurrent class loading.
-  static bool check_for_system_dictionary_modification(Dependencies* target);
+  static bool check_for_system_dictionary_modification(Dependencies* target, GraalEnv* env);
 
 public:
+  CompileTask* task() { return _task; }
+
   // Register the result of a compilation.
   static GraalEnv::CodeInstallResult register_method(
                        methodHandle&             target,
@@ -141,7 +152,7 @@
                        AbstractCompiler*         compiler,
                        DebugInformationRecorder* debug_info,
                        Dependencies*             dependencies,
-                       CompileTask*              task,
+                       GraalEnv*                 env,
                        int                       compile_id,
                        bool                      has_unsafe_access,
                        Handle                    installed_code,
--- a/src/share/vm/graal/graalJavaAccess.hpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Thu Feb 12 20:47:20 2015 +0100
@@ -84,7 +84,7 @@
     oop_field(HotSpotCompiledNmethod, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                     \
     int_field(HotSpotCompiledNmethod, entryBCI)                                                                                                                \
     int_field(HotSpotCompiledNmethod, id)                                                                                                                      \
-    long_field(HotSpotCompiledNmethod, ctask)                                                                                                                  \
+    long_field(HotSpotCompiledNmethod, graalEnv)                                                                                                               \
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledRuntimeStub)                                                                                                                      \
     oop_field(HotSpotCompiledRuntimeStub, stubName, "Ljava/lang/String;")                                                                                      \
@@ -96,15 +96,10 @@
     int_field(CompilationResult, totalFrameSize)                                                                                                               \
     int_field(CompilationResult, customStackAreaOffset)                                                                                                        \
     typeArrayOop_field(CompilationResult, targetCode, "[B")                                                                                                    \
-    oop_field(CompilationResult, assumptions, "Lcom/oracle/graal/api/code/Assumptions;")                                                                       \
+    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)                                                                                                                                     \
-    objArrayOop_field(Assumptions, list, "[Lcom/oracle/graal/api/code/Assumptions$Assumption;")                                                                \
-  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                                                                                                                                                    \
--- a/src/share/vm/graal/vmStructs_graal.hpp	Thu Feb 12 20:46:56 2015 +0100
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Thu Feb 12 20:47:20 2015 +0100
@@ -36,6 +36,8 @@
   nonstatic_field(ThreadShadow,  _pending_failed_speculation, oop)            \
   nonstatic_field(ThreadShadow,  _pending_transfer_to_interpreter, bool)      \
   nonstatic_field(MethodData,    _graal_node_count, int)                      \
+  nonstatic_field(GraalEnv,      _task, CompileTask*)                         \
+  nonstatic_field(GraalEnv,      _jvmti_can_hotswap_or_post_breakpoint, bool) \
 
 #define VM_TYPES_GRAAL(declare_type, declare_toplevel_type)                   \