changeset 19529:db19eba20b9c

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Sat, 21 Feb 2015 19:55:33 +0100
parents 82b5899f20cb (current diff) 34c0014aaf5b (diff)
children 863c42893cc4
files graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineControlFlowGraph.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineFrameStateBuilder.java graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineLoop.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeClassSubstitutionsTest.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsAssignableFromNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInstanceNode.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompositeValueClassSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeClassSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeSubstitutions.java graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraalDirectivePlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.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/LIRInstructionBase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/CompilationConstantNode.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 test/whitelist_baseline.txt
diffstat 922 files changed, 19658 insertions(+), 14316 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Sat Feb 21 19:47:33 2015 +0100
+++ b/.hgtags	Sat Feb 21 19:55:33 2015 +0100
@@ -525,3 +525,4 @@
 ae5b662550836e851c39e4fbb5c80517fc62488f graal-0.5
 3b60f720b955c466d913abb0113af9b38962950b graal-0.6
 1b0ef9634252c422b6f9839fc62eebc112545486 gpu-0.1
+9a12234da10cfa6934617274c203672389a1bbdd baseline-0.1
--- a/CHANGELOG.md	Sat Feb 21 19:47:33 2015 +0100
+++ b/CHANGELOG.md	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/Assumptions.java	Sat Feb 21 19:55:33 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/BailoutException.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BailoutException.java	Sat Feb 21 19:55:33 2015 +0100
@@ -48,6 +48,17 @@
     /**
      * Creates a new {@link BailoutException}.
      *
+     *
+     * @param args parameters to the formatter
+     */
+    public BailoutException(Throwable cause, String format, Object... args) {
+        super(String.format(Locale.ENGLISH, format, args), cause);
+        this.permanent = true;
+    }
+
+    /**
+     * Creates a new {@link BailoutException}.
+     *
      * @param permanent specifies whether this exception will occur again if compilation is retried
      * @param args parameters to the formatter
      */
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Sat Feb 21 19:55:33 2015 +0100
@@ -64,7 +64,7 @@
 
     /**
      * Creates a CSA layout.
-     * 
+     *
      * @param size size (in bytes) of the CSA. If this is {@code -1}, then the CSA size will be
      *            computed from {@code registers}.
      * @param slotSize the size (in bytes) of an {@linkplain #registerAt(int) indexable} slot in the
@@ -113,7 +113,7 @@
 
     /**
      * Gets the offset of a given register in the CSA.
-     * 
+     *
      * @return the offset (in bytes) of {@code reg} in the CSA
      * @throws IllegalArgumentException if {@code reg} does not have a slot in the CSA
      */
@@ -123,7 +123,7 @@
 
     /**
      * Gets the index of a given register in the CSA.
-     * 
+     *
      * @return the index of {@code reg} in the CSA
      * @throws IllegalArgumentException if {@code reg} does not have a slot in the CSA
      */
@@ -136,7 +136,7 @@
 
     /**
      * Gets the offset of a given register in the CSA.
-     * 
+     *
      * @return the offset (in bytes) of {@code reg} in the CSA
      * @throws IllegalArgumentException if {@code reg} does not have a slot in the CSA
      */
@@ -146,7 +146,7 @@
 
     /**
      * Determines if the CSA includes a slot for a given register.
-     * 
+     *
      * @param reg the register to test
      * @return true if the CSA contains a slot for {@code reg}
      */
@@ -156,7 +156,7 @@
 
     /**
      * Gets the register whose slot in the CSA is at a given index.
-     * 
+     *
      * @param index an index of a slot in the CSA
      * @return the register whose slot in the CSA is at {@code index} or {@code null} if
      *         {@code index} does not denote a slot in the CSA aligned with a register
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Sat Feb 21 19:55:33 2015 +0100
@@ -78,7 +78,7 @@
 
     /**
      * Creates a description of the registers and stack locations used by a call.
-     * 
+     *
      * @param stackSize amount of stack space (in bytes) required for the stack-based arguments of
      *            the call
      * @param returnLocation the location for the return value or {@link Value#ILLEGAL} if a void
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CompilationResult.java	Sat Feb 21 19:55:33 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,14 @@
 
     private ArrayList<CodeAnnotation> annotations;
 
-    private Assumptions assumptions;
+    private Assumption[] assumptions;
+
+    /**
+     * The list of the methods whose bytecodes were used as input to the compilation. If
+     * {@code null}, then the compilation did not record method dependencies. Otherwise, the first
+     * element of this array is the root method of the compilation.
+     */
+    private ResolvedJavaMethod[] methods;
 
     public CompilationResult() {
         this(null);
@@ -546,6 +554,9 @@
 
     @Override
     public String toString() {
+        if (methods != null) {
+            return getClass().getName() + "[" + methods[0].format("%H.%n(%p)%r") + "]";
+        }
         return identityHashCodeString(this);
     }
 
@@ -564,12 +575,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 +617,62 @@
         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.
+     *
+     * @param rootMethod the root method of the compilation
+     * @param inlinedMethods the methods inlined during compilation
+     */
+    public void setMethods(ResolvedJavaMethod rootMethod, Collection<ResolvedJavaMethod> inlinedMethods) {
+        assert rootMethod != null;
+        assert inlinedMethods != null;
+        if (inlinedMethods.contains(rootMethod)) {
+            methods = inlinedMethods.toArray(new ResolvedJavaMethod[inlinedMethods.size()]);
+            for (int i = 0; i < methods.length; i++) {
+                if (methods[i].equals(rootMethod)) {
+                    if (i != 0) {
+                        ResolvedJavaMethod tmp = methods[0];
+                        methods[0] = methods[i];
+                        methods[i] = tmp;
+                    }
+                    break;
+                }
+            }
+        } else {
+            methods = new ResolvedJavaMethod[1 + inlinedMethods.size()];
+            methods[0] = rootMethod;
+            int i = 1;
+            for (ResolvedJavaMethod m : inlinedMethods) {
+                methods[i++] = m;
+            }
+        }
+    }
+
+    /**
+     * Gets a fixed-size {@linkplain Arrays#asList(Object...) view} of the methods whose bytecodes
+     * were used as input to the compilation.
+     *
+     * @return {@code null} if the compilation did not record method dependencies otherwise the
+     *         methods whose bytecodes were used as input to the compilation with the first element
+     *         being the root method of the compilation
+     */
+    public Collection<ResolvedJavaMethod> getMethods() {
+        return methods == null ? null : Arrays.asList(methods);
     }
 
     public DataSection getDataSection() {
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DisassemblerProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DisassemblerProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,7 +29,7 @@
 
     /**
      * Gets a textual disassembly of some given installed code.
-     * 
+     *
      * @return a non-zero length string containing a disassembly of {@code code} or null if
      *         {@code code} is {@link InstalledCode#isValid() invalid} or it could not be
      *         disassembled for some other reason
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallLinkage.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallLinkage.java	Sat Feb 21 19:55:33 2015 +0100
@@ -57,7 +57,7 @@
 
     /**
      * Determines if the foreign call target destroys all registers.
-     * 
+     *
      * @return {@code true} if the register allocator must save all live registers around a call to
      *         this target
      */
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MemoryBarriers.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MemoryBarriers.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,7 +24,7 @@
 
 /**
  * Constants and intrinsic definition for memory barriers.
- * 
+ *
  * The documentation for each constant is taken from Doug Lea's <a
  * href="http://gee.cs.oswego.edu/dl/jmm/cookbook.html">The JSR-133 Cookbook for Compiler
  * Writers</a>.
@@ -32,14 +32,14 @@
  * The {@code JMM_*} constants capture the memory barriers necessary to implement the Java Memory
  * Model with respect to volatile field accesses. Their values are explained by this comment from
  * templateTable_i486.cpp in the HotSpot source code:
- * 
+ *
  * <pre>
  * Volatile variables demand their effects be made known to all CPU's in
  * order.  Store buffers on most chips allow reads &amp; writes to reorder; the
  * JMM's ReadAfterWrite.java test fails in -Xint mode without some kind of
  * memory barrier (i.e., it's not sufficient that the interpreter does not
  * reorder volatile references, the hardware also must not reorder them).
- * 
+ *
  * According to the new Java Memory Model (JMM):
  * (1) All volatiles are serialized wrt to each other.
  * ALSO reads &amp; writes act as acquire &amp; release, so:
@@ -50,7 +50,7 @@
  * that happen BEFORE the write float down to after the write.  It's OK for
  * non-volatile memory refs that happen after the volatile write to float up
  * before it.
- * 
+ *
  * We only put in barriers around volatile refs (they are expensive), not
  * _between_ memory refs (which would require us to track the flavor of the
  * previous memory refs).  Requirements (2) and (3) require some barriers
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterAttributes.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterAttributes.java	Sat Feb 21 19:55:33 2015 +0100
@@ -47,7 +47,7 @@
      * Creates a map from register {@linkplain Register#number numbers} to register
      * {@linkplain RegisterAttributes attributes} for a given register configuration and set of
      * registers.
-     * 
+     *
      * @param registerConfig a register configuration
      * @param registers a set of registers
      * @return an array whose length is the max register number in {@code registers} plus 1. An
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,7 +29,7 @@
 
 /**
  * Manages a list of unique deoptimization reasons.
- * 
+ *
  */
 public abstract class SpeculationLog {
     private volatile Object lastFailed;
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/TypeCheckHints.java	Sat Feb 21 19:55:33 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.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -106,7 +106,7 @@
 
     @Test
     public void testDuplicate() {
-        test("verifyDuplicateSnippet", 42);
+        // test("verifyDuplicateSnippet", 42);
         test("preventDuplicateSnippet", 42);
     }
 
--- a/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/IterationDirectiveTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/IterationDirectiveTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -51,7 +51,7 @@
 
     @Override
     protected boolean checkLowTierGraph(StructuredGraph graph) {
-        NodeIterable<LoopBeginNode> loopBeginNodes = graph.getNodes(LoopBeginNode.class);
+        NodeIterable<LoopBeginNode> loopBeginNodes = graph.getNodes(LoopBeginNode.TYPE);
         Assert.assertEquals("LoopBeginNode count", 1, loopBeginNodes.count());
 
         LoopBeginNode loopBeginNode = loopBeginNodes.first();
--- a/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/OpaqueDirectiveTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/OpaqueDirectiveTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -123,7 +123,7 @@
     @Override
     protected boolean checkLowTierGraph(StructuredGraph graph) {
         OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);
-        for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) {
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
             Assert.assertEquals(snippet.expectedReturnNode(), returnNode.result().getClass());
         }
         return true;
--- a/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ProbabilityDirectiveTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ProbabilityDirectiveTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -48,7 +48,7 @@
 
     @Override
     protected boolean checkLowTierGraph(StructuredGraph graph) {
-        NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.class);
+        NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
         Assert.assertEquals("IfNode count", 1, ifNodes.count());
 
         IfNode ifNode = ifNodes.first();
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java	Sat Feb 21 19:55:33 2015 +0100
@@ -46,6 +46,15 @@
         assert !Double.isNaN(notRecordedProbability);
         this.notRecordedProbability = notRecordedProbability;
         assert isSorted();
+        assert totalProbablility() >= 0 && totalProbablility() <= 1.0001 : totalProbablility() + " " + this;
+    }
+
+    private double totalProbablility() {
+        double total = notRecordedProbability;
+        for (T item : pitems) {
+            total += item.probability;
+        }
+        return total;
     }
 
     /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/BytecodeDisassemblerProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/BytecodeDisassemblerProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
     /**
      * Gets a textual disassembly of the bytecode for a given method. In the absence of bytecode
      * rewriting, disassembling a method will produce the same result.
-     * 
+     *
      * @return a non-zero length string containing a disassembly of {@code method}'s bytecode or
      *         null if {@code method} has no bytecode (i.e., {@code method.getCodeSize() == 0})
      */
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ExceptionHandler.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ExceptionHandler.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,7 +37,7 @@
 
     /**
      * Creates a new exception handler with the specified ranges.
-     * 
+     *
      * @param startBCI the start index of the protected range
      * @param endBCI the end index of the protected range
      * @param catchBCI the index of the handler
@@ -83,7 +83,7 @@
 
     /**
      * Checks whether this handler catches all exceptions.
-     * 
+     *
      * @return {@code true} if this handler catches all exceptions
      */
     public boolean isCatchAll() {
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java	Sat Feb 21 19:55:33 2015 +0100
@@ -41,6 +41,21 @@
         public static TriState get(boolean value) {
             return value ? TRUE : FALSE;
         }
+
+        /**
+         * This is optimistic about {@link #UNKNOWN} (it prefers known values over {@link #UNKNOWN})
+         * and pesimistic about known (it perfers {@link #TRUE} over {@link #FALSE}).
+         */
+        public static TriState merge(TriState a, TriState b) {
+            if (a == TRUE || b == TRUE) {
+                return TRUE;
+            }
+            if (a == FALSE || b == FALSE) {
+                return FALSE;
+            }
+            assert a == UNKNOWN && b == UNKNOWN;
+            return UNKNOWN;
+        }
     }
 
     /**
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Sat Feb 21 19:55:33 2015 +0100
@@ -282,7 +282,7 @@
 
     /**
      * Checks whether the method has a receiver parameter - i.e., whether it is not static.
-     * 
+     *
      * @return whether the method has a receiver parameter
      */
     default boolean hasReceiver() {
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,7 +38,7 @@
 
     /**
      * Creates an {@link AMD64Address} with given base register, no scaling and no displacement.
-     * 
+     *
      * @param base the base register
      */
     public AMD64Address(Register base) {
@@ -48,7 +48,7 @@
     /**
      * Creates an {@link AMD64Address} with given base register, no scaling and a given
      * displacement.
-     * 
+     *
      * @param base the base register
      * @param displacement the displacement
      */
@@ -59,7 +59,7 @@
     /**
      * Creates an {@link AMD64Address} with given base and index registers, scaling and
      * displacement. This is the most general constructor.
-     * 
+     *
      * @param base the base register
      * @param index the index register
      * @param scale the scaling factor
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,803 +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.baseline;
-
-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.common.*;
-import com.oracle.graal.compiler.common.alloc.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.compiler.gen.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.BlockEndOp;
-import com.oracle.graal.lir.alloc.lsra.*;
-import com.oracle.graal.lir.framemap.*;
-import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.stackslotalloc.*;
-import com.oracle.graal.phases.*;
-
-public class BaselineBytecodeParser extends AbstractBytecodeParser<Value, BaselineFrameStateBuilder> implements BytecodeParserTool {
-    private Backend backend;
-    protected LIRGeneratorTool gen;
-    private LIRGenerationResult lirGenRes;
-    private BytecodeLIRBuilder lirBuilder;
-    @SuppressWarnings("unused") private BciBlock[] loopHeaders;
-    private LocalLiveness liveness;
-    private BciBlockBitMap blockVisited;
-
-    private static class BciBlockBitMap {
-        BitSet bitSet;
-
-        public BciBlockBitMap(BciBlockMapping blockMap) {
-            bitSet = new BitSet(blockMap.getBlocks().length);
-        }
-
-        public boolean get(BciBlock block) {
-            return bitSet.get(block.getId());
-        }
-
-        public void set(BciBlock block) {
-            bitSet.set(block.getId());
-        }
-    }
-
-    public BaselineBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts,
-                    BaselineFrameStateBuilder frameState, Backend backend) {
-
-        super(metaAccess, method, graphBuilderConfig, optimisticOpts);
-        this.backend = backend;
-        this.setCurrentFrameState(frameState);
-    }
-
-    public LIRGenerationResult getLIRGenerationResult() {
-        return lirGenRes;
-    }
-
-    protected void build() {
-        if (PrintProfilingInformation.getValue()) {
-            TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
-            TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
-        }
-
-        try (Indent indent = Debug.logAndIndent("build graph for %s", method)) {
-
-            BciBlockMapping blockMap;
-            try (Scope ds = Debug.scope("BciBlockMapping")) {
-                // compute the block map, setup exception handlers and get the entrypoint(s)
-                blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis(), false);
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-
-            loopHeaders = blockMap.getLoopHeaders();
-            liveness = blockMap.liveness;
-            blockVisited = new BciBlockBitMap(blockMap);
-
-            if (method.isSynchronized()) {
-                throw GraalInternalError.unimplemented("Handle synchronized methods");
-            }
-
-            frameState = new BaselineFrameStateBuilder(method);
-            frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
-
-            currentBlock = blockMap.startBlock;
-            blockMap.startBlock.setEntryState(0, frameState);
-            if (blockMap.startBlock.isLoopHeader) {
-                throw GraalInternalError.unimplemented("Handle start block as loop header");
-            }
-
-            // add loops ? how do we add looks when we haven't parsed the bytecode?
-
-            // create the control flow graph
-            BaselineControlFlowGraph cfg = BaselineControlFlowGraph.compute(blockMap);
-
-            // create the LIR
-            List<? extends AbstractBlock<?>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.getBlocks().length, blockMap.startBlock);
-            List<? extends AbstractBlock<?>> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.getBlocks().length, blockMap.startBlock);
-            LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder);
-
-            RegisterConfig registerConfig = null;
-            FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
-            TargetDescription target = backend.getTarget();
-            CallingConvention cc = CodeUtil.getCallingConvention(backend.getProviders().getCodeCache(), CallingConvention.Type.JavaCallee, method, false);
-            this.lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, method, null);
-            this.gen = backend.newLIRGenerator(cc, lirGenRes);
-            this.lirBuilder = backend.newBytecodeLIRBuilder(gen, this);
-
-            try (Scope ds = Debug.scope("BackEnd", lir)) {
-                try (Scope s = Debug.scope("LIRGen", gen)) {
-
-                    // possibly add all the arguments to slots in the local variable array
-
-                    for (BciBlock block : blockMap.getBlocks()) {
-                        emitBlock(block);
-                    }
-
-                    gen.beforeRegisterAllocation();
-                    Debug.dump(lir, "After LIR generation");
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-
-                try (Scope s = Debug.scope("Allocator")) {
-                    if (backend.shouldAllocateRegisters()) {
-                        LinearScan.allocate(target, lirGenRes);
-                    }
-                }
-                try (Scope s1 = Debug.scope("BuildFrameMap")) {
-                    // build frame map
-                    lirGenRes.buildFrameMap(new SimpleStackSlotAllocator());
-                    Debug.dump(lir, "After FrameMap building");
-                }
-                try (Scope s1 = Debug.scope("MarkLocations")) {
-                    if (backend.shouldAllocateRegisters()) {
-                        // currently we mark locations only if we do register allocation
-                        LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
-                    }
-                }
-
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
-    private void emitBlock(BciBlock b) {
-        if (lirGenRes.getLIR().getLIRforBlock(b) == null) {
-            for (BciBlock pred : b.getPredecessors()) {
-                if (!b.isLoopHeader() || !pred.isLoopEnd()) {
-                    emitBlock(pred);
-                }
-            }
-            processBlock(b);
-        }
-    }
-
-    @Override
-    protected void handleUnresolvedLoadConstant(JavaType type) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedCheckCast(JavaType type, Value object) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedInstanceOf(JavaType type, Value object) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedNewInstance(JavaType type) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedNewObjectArray(JavaType type, Value length) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedNewMultiArray(JavaType type, List<Value> dims) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedLoadField(JavaField field, Value receiver) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedStoreField(JavaField field, Value value, Value receiver) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void handleUnresolvedExceptionType(JavaType type) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genLoadIndexed(Value index, Value array, Kind kind) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genStoreIndexed(Value array, Value index, Kind kind, Value value) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genIntegerAdd(Kind kind, Value x, Value y) {
-        return gen.emitAdd(x, y, false);
-    }
-
-    @Override
-    protected Value genIntegerSub(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genIntegerMul(Kind kind, Value x, Value y) {
-        return gen.emitMul(x, y, false);
-    }
-
-    @Override
-    protected Value genFloatAdd(Kind kind, Value x, Value y, boolean isStrictFP) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genFloatSub(Kind kind, Value x, Value y, boolean isStrictFP) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genFloatMul(Kind kind, Value x, Value y, boolean isStrictFP) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genFloatDiv(Kind kind, Value x, Value y, boolean isStrictFP) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genFloatRem(Kind kind, Value x, Value y, boolean isStrictFP) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genIntegerDiv(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genIntegerRem(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genNegateOp(Value x) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genLeftShift(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genRightShift(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genUnsignedRightShift(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genAnd(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genOr(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genXor(Kind kind, Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genNormalizeCompare(Value x, Value y, boolean isUnorderedLess) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genFloatConvert(FloatConvert op, Value input) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genNarrow(Value input, int bitCount) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genSignExtend(Value input, int bitCount) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genZeroExtend(Value input, int bitCount) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genObjectEquals(Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genIntegerEquals(Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genIf(Value x, Condition cond, Value y) {
-        assert currentBlock.getSuccessors().size() == 2;
-        BciBlock trueBlock = currentBlock.getSuccessors().get(0);
-        BciBlock falseBlock = currentBlock.getSuccessors().get(1);
-        if (trueBlock == falseBlock) {
-            genGoto();
-            return;
-        }
-
-        double probability = branchProbability();
-
-        LabelRef trueDestination = getSuccessor(0);
-        LabelRef falseDestination = getSuccessor(1);
-
-        gen.emitCompareBranch(x.getKind(), x, y, cond, false, trueDestination, falseDestination, probability);
-    }
-
-    @Override
-    protected Value genIntegerLessThan(Value x, Value y) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genUnique(Value x) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genThrow() {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value createCheckCast(ResolvedJavaType type, Value object, JavaTypeProfile profileForTypeCheck, boolean b) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value createInstanceOf(ResolvedJavaType type, Value object, JavaTypeProfile profileForTypeCheck) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genConditional(Value x) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value createNewInstance(ResolvedJavaType type, boolean fillContents) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value createNewArray(ResolvedJavaType elementType, Value length, boolean fillContents) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value createNewMultiArray(ResolvedJavaType type, List<Value> dims) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genLoadField(Value receiver, ResolvedJavaField field) {
-        if (field.isStatic()) {
-            Value classRef = lirBuilder.getClassConstant(field.getDeclaringClass());
-            long displacement = lirBuilder.getFieldOffset(field);
-            Value address = gen.emitAddress(classRef, displacement, Value.ILLEGAL, 0);
-            LIRKind readKind = backend.getTarget().getLIRKind(field.getKind());
-            LIRFrameState state = createFrameState(frameState);
-            return gen.emitLoad(readKind, address, state);
-        }
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void emitNullCheck(Value receiver) {
-        gen.emitNullCheck(receiver, createFrameState(frameState));
-    }
-
-    @Override
-    protected void emitBoundsCheck(Value index, Value length) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genArrayLength(Value array) {
-        emitNullCheck(array);
-        long displacement = lirBuilder.getArrayLengthOffset();
-        Value address = gen.emitAddress(array, displacement, Value.ILLEGAL, 0);
-        LIRKind readKind = backend.getTarget().getLIRKind(Kind.Int);
-        LIRFrameState state = createFrameState(frameState);
-        return gen.emitLoad(readKind, address, state);
-    }
-
-    private LIRFrameState createFrameState(BaselineFrameStateBuilder state) {
-        LabelRef exceptionEdge = null;
-        BytecodeFrame caller = null;
-        boolean duringCall = false;
-        int numLocals = state.localsSize();
-        int numStack = state.stackSize();
-        int numLocks = state.lockDepth();
-        JavaValue[] values = new JavaValue[numLocals + numStack + numLocks];
-
-        for (int i = 0; i < numLocals; i++) {
-            values[i] = (JavaValue) state.localAt(i);
-        }
-
-        for (int i = 0; i < numStack; i++) {
-            values[numLocals + i] = (JavaValue) state.stackAt(i);
-        }
-
-        for (int i = 0; i < numStack; i++) {
-            values[numLocals + numStack + i] = (JavaValue) state.lockAt(i);
-        }
-
-        BytecodeFrame frame = new BytecodeFrame(caller, method, bci(), state.rethrowException(), duringCall, values, numLocals, numStack, numLocks);
-        return new LIRFrameState(frame, null, exceptionEdge);
-    }
-
-    @Override
-    protected Value genStoreField(Value receiver, ResolvedJavaField field, Value value) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genInvokeStatic(JavaMethod target) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genInvokeInterface(JavaMethod target) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genInvokeDynamic(JavaMethod target) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genInvokeVirtual(JavaMethod target) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genInvokeSpecial(JavaMethod target) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genReturn(Value x) {
-        gen.emitReturn(x);
-    }
-
-    @Override
-    protected Value genMonitorEnter(Value x) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value genMonitorExit(Value x, Value returnValue) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genJsr(int dest) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genRet(int localIndex) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected void genIntegerSwitch(Value value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
-        // TODO Auto-generated method stub
-        throw GraalInternalError.unimplemented("Auto-generated method stub");
-    }
-
-    @Override
-    protected Value appendConstant(JavaConstant constant) {
-        return gen.emitLoadConstant(constant.getLIRKind(), constant);
-    }
-
-    @Override
-    protected Value append(Value v) {
-        return v;
-    }
-
-    private void createTarget(BciBlock block) {
-        assert block != null && frameState != null;
-        assert !block.isExceptionEntry || frameState.stackSize() == 1;
-
-        if (!blockVisited.get(block)) {
-            /*
-             * This is the first time we see this block as a branch target. Create and return a
-             * placeholder that later can be replaced with a MergeNode when we see this block again.
-             */
-            blockVisited.set(block);
-            if (block.getPredecessorCount() > 1) {
-                /*
-                 * If there are more than one predecessors we have to ensure that we are not passing
-                 * constants to the new framestate otherwise we will get interfacing problems.
-                 */
-                moveConstantsToVariables();
-            }
-            block.setEntryState(0, frameState.copy());
-            block.getEntryState(0).clearNonLiveLocals(block, liveness, true);
-
-            Debug.log("createTarget %s: first visit", block);
-            return;
-        }
-
-        // We already saw this block before, so we have to merge states.
-        if (!((BaselineFrameStateBuilder) block.getEntryState(0)).isCompatibleWith(frameState)) {
-            throw new BailoutException("stacks do not match; bytecodes would not verify");
-        }
-
-        if (block.isLoopHeader) {
-            assert currentBlock == null || currentBlock.getId() >= block.getId() : "must be backward branch";
-            if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) {
-                // this is the only successor of the current block so we can adjust
-                adaptFramestate((BaselineFrameStateBuilder) block.getEntryState(0));
-                return;
-            }
-            GraalInternalError.unimplemented("Loops not yet supported");
-        }
-        assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
-
-        /*
-         * This is the second time we see this block. Create the actual MergeNode and the End Node
-         * for the already existing edge. For simplicity, we leave the placeholder in the graph and
-         * just append the new nodes after the placeholder.
-         */
-        if (currentBlock != null && currentBlock.numNormalSuccessors() == 1) {
-            // this is the only successor of the current block so we can adjust
-            adaptFramestate((BaselineFrameStateBuilder) block.getEntryState(0));
-            return;
-        }
-        GraalInternalError.unimplemented("second block visit not yet implemented");
-
-        // merge frame states e.g. block.entryState.merge(mergeNode, target.state);
-
-        Debug.log("createTarget %s: merging state", block);
-    }
-
-    private void moveConstantsToVariables() {
-        Debug.log("moveConstantsToVariables: framestate before: %s", frameState);
-        for (int i = 0; i < frameState.stackSize(); i++) {
-            Value src = frameState.stackAt(i);
-            if (src instanceof JavaConstant) {
-                AllocatableValue dst = gen.newVariable(src.getLIRKind());
-                gen.emitMove(dst, src);
-                frameState.storeStack(i, dst);
-                Debug.log("introduce new variabe %s for stackslot %d (end of block %s", dst, i, currentBlock);
-            }
-        }
-        for (int i = 0; i < frameState.localsSize(); i++) {
-            Value src = frameState.localAt(i);
-            if (src instanceof JavaConstant) {
-                AllocatableValue dst = gen.newVariable(src.getLIRKind());
-                gen.emitMove(dst, src);
-                frameState.storeLocal(i, dst);
-                Debug.log("introduce new variabe %s for local %d (end of block %s", dst, i, currentBlock);
-            }
-        }
-        Debug.log("moveConstantsToVariables: framestate after: %s", frameState);
-    }
-
-    private static void adaptValues(Value dst, Value src, PhiResolver resolver) {
-        if (dst == null) {
-            return;
-        }
-        assert src != null : "Source is null but Destination is not!";
-
-        if (!dst.equals(src)) {
-            resolver.move(dst, src);
-        }
-    }
-
-    private void adaptFramestate(BaselineFrameStateBuilder other) {
-        assert frameState.isCompatibleWith(other) : "framestates not compatible!";
-        PhiResolver resolver = new PhiResolver(gen);
-        for (int i = 0; i < frameState.stackSize(); i++) {
-            Value src = frameState.stackAt(i);
-            Value dst = other.stackAt(i);
-            adaptValues(dst, src, resolver);
-        }
-        for (int i = 0; i < frameState.localsSize(); i++) {
-            Value src = frameState.localAt(i);
-            Value dst = other.localAt(i);
-            adaptValues(dst, src, resolver);
-        }
-        resolver.dispose();
-    }
-
-    protected void processBlock(BciBlock block) {
-        frameState = (BaselineFrameStateBuilder) block.getEntryState(0);
-        setCurrentFrameState(frameState);
-        currentBlock = block;
-        iterateBytecodesForBlock(block);
-    }
-
-    private boolean isBlockEnd() {
-        List<LIRInstruction> l = gen.getResult().getLIR().getLIRforBlock(currentBlock);
-        if (l.isEmpty()) {
-            return false;
-        }
-        return l.get(l.size() - 1) instanceof BlockEndOp;
-    }
-
-    @Override
-    protected void iterateBytecodesForBlock(BciBlock block) {
-        gen.doBlockStart(block);
-
-        if (block == gen.getResult().getLIR().getControlFlowGraph().getStartBlock()) {
-            assert block.getPredecessorCount() == 0;
-            lirBuilder.emitPrologue(method);
-        } else {
-            assert block.getPredecessorCount() > 0;
-        }
-
-        if (block.isLoopHeader) {
-            /*
-             * We need to preserve the frame state builder of the loop header so that we can merge
-             * values for phi functions, so make a copy of it.
-             */
-            block.setEntryState(0, frameState.copy());
-
-        }
-        int endBCI = stream.endBCI();
-
-        stream.setBCI(block.startBci);
-        int bci = block.startBci;
-        BytecodesParsed.add(block.endBci - bci);
-
-        while (bci < endBCI) {
-
-            // read the opcode
-            int opcode = stream.currentBC();
-            // traceState();
-            traceInstruction(bci, opcode, bci == block.startBci);
-
-            processBytecode(bci, opcode);
-
-            stream.next();
-            bci = stream.currentBCI();
-
-            if (isBlockEnd()) {
-                break;
-            }
-
-            if (bci < endBCI) {
-                if (bci > block.endBci) {
-                    if (block.numNormalSuccessors() == 1) {
-                        assert !block.getSuccessor(0).isExceptionEntry;
-                        // we fell through to the next block, add a goto and break
-                        genGoto();
-                    }
-                    break;
-                }
-            }
-        }
-
-        assert LIR.verifyBlock(gen.getResult().getLIR(), block);
-        gen.doBlockEnd(block);
-    }
-
-    public void storeLocal(int i, Value x) {
-        frameState.storeLocal(i, x);
-    }
-
-    LabelRef getSuccessor(int index) {
-        createTarget(currentBlock.getSuccessor(index));
-        return LabelRef.forSuccessor(lirGenRes.getLIR(), currentBlock, index);
-    }
-
-    @Override
-    protected void genGoto() {
-        gen.emitJump(getSuccessor(0));
-    }
-
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineCompiler.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +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.graal.baseline;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.bytecode.*;
-import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.java.*;
-import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.phases.*;
-
-/**
- * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
- */
-@SuppressWarnings("all")
-public class BaselineCompiler {
-
-    public BaselineCompiler(GraphBuilderConfiguration graphBuilderConfig, MetaAccessProvider metaAccess) {
-        this.graphBuilderConfig = graphBuilderConfig;
-        this.metaAccess = metaAccess;
-    }
-
-    private final MetaAccessProvider metaAccess;
-
-    private final GraphBuilderConfiguration graphBuilderConfig;
-
-    public CompilationResult generate(ResolvedJavaMethod method, int entryBCI, Backend backend, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
-                    CompilationResultBuilderFactory factory, OptimisticOptimizations optimisticOpts, Replacements replacements) {
-        assert method.getCode() != null : "method must contain bytecodes: " + method;
-        TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
-
-        BaselineFrameStateBuilder frameState = new BaselineFrameStateBuilder(method);
-
-        BaselineBytecodeParser parser = new BaselineBytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, frameState, backend);
-
-        // build blocks and LIR instructions
-        try {
-            parser.build();
-        } finally {
-            filter.remove();
-        }
-
-        // emitCode
-        Assumptions assumptions = new Assumptions(OptAssumptions.getValue());
-        GraalCompiler.emitCode(backend, assumptions, parser.getLIRGenerationResult(), compilationResult, installedCodeOwner, factory);
-
-        return compilationResult;
-    }
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineControlFlowGraph.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +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.baseline;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.java.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-
-public final class BaselineControlFlowGraph implements AbstractControlFlowGraph<BciBlock> {
-
-    private BciBlock[] blocks;
-    private Collection<Loop<BciBlock>> loops;
-
-    public static BaselineControlFlowGraph compute(BciBlockMapping blockMap) {
-        try (Scope ds = Debug.scope("BaselineCFG", blockMap)) {
-            BaselineControlFlowGraph cfg = new BaselineControlFlowGraph(blockMap);
-            cfg.computePredecessors();
-            cfg.computeLoopInformation(blockMap);
-            AbstractControlFlowGraph.computeDominators(cfg);
-
-            assert CFGVerifier.verify(cfg);
-
-            return cfg;
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
-    private BaselineControlFlowGraph(BciBlockMapping blockMap) {
-        blocks = blockMap.getBlocks();
-        loops = new ArrayList<>();
-    }
-
-    public List<BciBlock> getBlocks() {
-        return Arrays.asList(blocks);
-    }
-
-    public Collection<Loop<BciBlock>> getLoops() {
-        return loops;
-    }
-
-    public BciBlock getStartBlock() {
-        if (blocks.length > 0) {
-            return blocks[0];
-        }
-        return null;
-    }
-
-    /**
-     * Create and populate the predecessor list.
-     */
-    private void computePredecessors() {
-        // set predecessors
-        for (BciBlock block : blocks) {
-            block.setPredecessors(new ArrayList<>(4));
-        }
-        // calculate predecessors
-        for (BciBlock block : blocks) {
-            for (BciBlock succ : block.getSuccessors()) {
-                succ.getPredecessors().add(block);
-            }
-        }
-    }
-
-    private void computeLoopInformation(BciBlockMapping blockMap) {
-        try (Indent indent = Debug.logAndIndent("computeLoopInformation")) {
-            for (BciBlock block : blocks) {
-                calcLoop(block, blockMap);
-                Debug.log("Block: %s, Loop: %s", block, block.getLoop());
-            }
-        }
-    }
-
-    private Loop<BciBlock> getLoop(int index, BciBlockMapping blockMap) {
-        BciBlock header = blockMap.getLoopHeader(index);
-        assert header.getLoopDepth() > 0;
-        Loop<BciBlock> loop = header.getLoop();
-
-        if (loop == null) {
-            Loop<BciBlock> parent = null;
-
-            if (header.getLoopDepth() > 1) {
-                // Recursively create out loops.
-                Iterator<Integer> i = header.loopIdIterable().iterator();
-                assert i.hasNext() : "BciBlock.loopIdIterable() must return exactly BciBlock.getLoopDepth() elements!";
-                int outerLoopId = i.next();
-                assert index == outerLoopId : "The first loopId must be the id of the loop that is started by this header!";
-                assert i.hasNext() : "BciBlock.loopIdIterable() must return exactly BciBlock.getLoopDepth() elements!";
-                outerLoopId = i.next();
-                parent = getLoop(outerLoopId, blockMap);
-            }
-
-            loop = new BaselineLoop(parent, index, header);
-            loops.add(loop);
-            header.setLoop(loop);
-        }
-        return loop;
-    }
-
-    private void calcLoop(BciBlock block, BciBlockMapping blockMap) {
-        int loopId = block.getLoopId();
-        if (loopId != -1) {
-            block.setLoop(getLoop(loopId, blockMap));
-
-        }
-    }
-
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineFrameStateBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +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.baseline;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.*;
-
-public class BaselineFrameStateBuilder extends AbstractFrameStateBuilder<Value, BaselineFrameStateBuilder> {
-
-    private static final Value[] EMPTY_ARRAY = new Value[0];
-
-    public BaselineFrameStateBuilder(ResolvedJavaMethod method) {
-        // we always need at least one stack slot (for exceptions)
-        super(method);
-    }
-
-    protected BaselineFrameStateBuilder(BaselineFrameStateBuilder other) {
-        super(other);
-    }
-
-    @Override
-    protected Value[] allocateArray(int length) {
-        return length == 0 ? EMPTY_ARRAY : new Value[length];
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("[locals: [");
-        for (int i = 0; i < locals.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(locals[i] == null ? "_" : locals[i].toString());
-        }
-        sb.append("] stack: [");
-        for (int i = 0; i < stackSize; i++) {
-            sb.append(i == 0 ? "" : ",").append(stack[i] == null ? "_" : stack[i].toString());
-        }
-        sb.append("] locks: [");
-        for (int i = 0; i < lockedObjects.length; i++) {
-            sb.append(i == 0 ? "" : ",").append(lockedObjects[i].toString());
-        }
-        sb.append("]");
-        if (rethrowException) {
-            sb.append(" rethrowException");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    @Override
-    public BaselineFrameStateBuilder copy() {
-        return new BaselineFrameStateBuilder(this);
-    }
-
-    private static boolean isCompatible(Value x, Value y) {
-        if (x == null && y == null) {
-            return true;
-        }
-        if ((x == null || y == null) || (x.getKind() != y.getKind())) {
-            return false;
-        }
-        return true;
-
-    }
-
-    @Override
-    public boolean isCompatibleWith(BaselineFrameStateBuilder other) {
-        assert method.equals(other.method) && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
-
-        if (stackSize() != other.stackSize()) {
-            return false;
-        }
-        for (int i = 0; i < stackSize(); i++) {
-            if (!isCompatible(stackAt(i), other.stackAt(i))) {
-                return false;
-            }
-        }
-        if (lockedObjects.length != other.lockedObjects.length) {
-            return false;
-        }
-        return true;
-    }
-}
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineLoop.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +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.baseline;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
-
-public class BaselineLoop extends Loop<BciBlock> {
-
-    protected BaselineLoop(Loop<BciBlock> parent, int index, BciBlock header) {
-        super(parent, index, header);
-    }
-
-    @Override
-    public long numBackedges() {
-        // currently only loops with one backedge are supported
-        return 1;
-    }
-
-}
--- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeLookupSwitch.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeLookupSwitch.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,7 +34,7 @@
 
     /**
      * Constructor for a {@link BytecodeStream}.
-     * 
+     *
      * @param stream the {@code BytecodeStream} containing the switch instruction
      * @param bci the index in the stream of the switch instruction
      */
--- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,7 +36,7 @@
 
     /**
      * Creates a new {@code BytecodeStream} for the specified bytecode.
-     * 
+     *
      * @param code the array of bytes that contains the bytecode
      */
     public BytecodeStream(byte[] code) {
@@ -54,7 +54,7 @@
 
     /**
      * Gets the next bytecode index (no side-effects).
-     * 
+     *
      * @return the next bytecode index
      */
     public int nextBCI() {
@@ -63,7 +63,7 @@
 
     /**
      * Gets the current bytecode index.
-     * 
+     *
      * @return the current bytecode index
      */
     public int currentBCI() {
@@ -72,7 +72,7 @@
 
     /**
      * Gets the bytecode index of the end of the code.
-     * 
+     *
      * @return the index of the end of the code
      */
     public int endBCI() {
@@ -82,7 +82,7 @@
     /**
      * Gets the current opcode. This method will never return the {@link Bytecodes#WIDE WIDE}
      * opcode, but will instead return the opcode that is modified by the {@code WIDE} opcode.
-     * 
+     *
      * @return the current opcode; {@link Bytecodes#END} if at or beyond the end of the code
      */
     public int currentBC() {
@@ -96,7 +96,7 @@
     /**
      * Reads the index of a local variable for one of the load or store instructions. The WIDE
      * modifier is handled internally.
-     * 
+     *
      * @return the index of the local variable
      */
     public int readLocalIndex() {
@@ -109,7 +109,7 @@
 
     /**
      * Read the delta for an {@link Bytecodes#IINC} bytecode.
-     * 
+     *
      * @return the delta for the {@code IINC}
      */
     public int readIncrement() {
@@ -122,7 +122,7 @@
 
     /**
      * Read the destination of a {@link Bytecodes#GOTO} or {@code IF} instructions.
-     * 
+     *
      * @return the destination bytecode index
      */
     public int readBranchDest() {
@@ -136,7 +136,7 @@
 
     /**
      * Read a signed 4-byte integer from the bytecode stream at the specified bytecode index.
-     * 
+     *
      * @param bci the bytecode index
      * @return the integer value
      */
@@ -147,7 +147,7 @@
 
     /**
      * Reads an unsigned, 1-byte value from the bytecode stream at the specified bytecode index.
-     * 
+     *
      * @param bci the bytecode index
      * @return the byte
      */
@@ -157,7 +157,7 @@
 
     /**
      * Reads a constant pool index for the current instruction.
-     * 
+     *
      * @return the constant pool index
      */
     public char readCPI() {
@@ -169,7 +169,7 @@
 
     /**
      * Reads a constant pool index for an invokedynamic instruction.
-     * 
+     *
      * @return the constant pool index
      */
     public int readCPI4() {
@@ -179,7 +179,7 @@
 
     /**
      * Reads a signed, 1-byte value for the current instruction (e.g. BIPUSH).
-     * 
+     *
      * @return the byte
      */
     public byte readByte() {
@@ -188,7 +188,7 @@
 
     /**
      * Reads a signed, 2-byte short for the current instruction (e.g. SIPUSH).
-     * 
+     *
      * @return the short value
      */
     public short readShort() {
@@ -199,7 +199,7 @@
      * Sets the bytecode index to the specified value. If {@code bci} is beyond the end of the
      * array, {@link #currentBC} will return {@link Bytecodes#END} and other methods may throw
      * {@link ArrayIndexOutOfBoundsException}.
-     * 
+     *
      * @param bci the new bytecode index
      */
     public void setBCI(int bci) {
--- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeSwitch.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeSwitch.java	Sat Feb 21 19:55:33 2015 +0100
@@ -44,7 +44,7 @@
 
     /**
      * Constructor for a {@link BytecodeStream}.
-     * 
+     *
      * @param stream the {@code BytecodeStream} containing the switch instruction
      * @param bci the index in the stream of the switch instruction
      */
@@ -56,7 +56,7 @@
 
     /**
      * Gets the current bytecode index.
-     * 
+     *
      * @return the current bytecode index
      */
     public int bci() {
@@ -65,7 +65,7 @@
 
     /**
      * Gets the index of the instruction denoted by the {@code i}'th switch target.
-     * 
+     *
      * @param i index of the switch target
      * @return the index of the instruction denoted by the {@code i}'th switch target
      */
@@ -75,7 +75,7 @@
 
     /**
      * Gets the index of the instruction for the default switch target.
-     * 
+     *
      * @return the index of the instruction for the default switch target
      */
     public int defaultTarget() {
@@ -84,7 +84,7 @@
 
     /**
      * Gets the offset from the start of the switch instruction to the default switch target.
-     * 
+     *
      * @return the offset to the default switch target
      */
     public int defaultOffset() {
@@ -93,7 +93,7 @@
 
     /**
      * Gets the key at {@code i}'th switch target index.
-     * 
+     *
      * @param i the switch target index
      * @return the key at {@code i}'th switch target index
      */
@@ -101,7 +101,7 @@
 
     /**
      * Gets the offset from the start of the switch instruction for the {@code i}'th switch target.
-     * 
+     *
      * @param i the switch target index
      * @return the offset to the {@code i}'th switch target
      */
@@ -109,14 +109,14 @@
 
     /**
      * Gets the number of switch targets.
-     * 
+     *
      * @return the number of switch targets
      */
     public abstract int numberOfCases();
 
     /**
      * Gets the total size in bytes of the switch instruction.
-     * 
+     *
      * @return the total size in bytes of the switch instruction
      */
     public abstract int size();
--- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeTableSwitch.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeTableSwitch.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,7 +34,7 @@
 
     /**
      * Constructor for a {@link BytecodeStream}.
-     * 
+     *
      * @param stream the {@code BytecodeStream} containing the switch instruction
      * @param bci the index in the stream of the switch instruction
      */
@@ -44,7 +44,7 @@
 
     /**
      * Gets the low key of the table switch.
-     * 
+     *
      * @return the low key
      */
     public int lowKey() {
@@ -53,7 +53,7 @@
 
     /**
      * Gets the high key of the table switch.
-     * 
+     *
      * @return the high key
      */
     public int highKey() {
--- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytes.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytes.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,7 +29,7 @@
 
     /**
      * Gets a signed 1-byte value.
-     * 
+     *
      * @param data the array containing the data
      * @param bci the start index of the value to retrieve
      * @return the signed 1-byte value at index {@code bci} in array {@code data}
@@ -40,7 +40,7 @@
 
     /**
      * Gets a signed 2-byte big-endian value.
-     * 
+     *
      * @param data the array containing the data
      * @param bci the start index of the value to retrieve
      * @return the signed 2-byte, big-endian, value at index {@code bci} in array {@code data}
@@ -51,7 +51,7 @@
 
     /**
      * Gets an unsigned 1-byte value.
-     * 
+     *
      * @param data the array containing the data
      * @param bci the start index of the value to retrieve
      * @return the unsigned 1-byte value at index {@code bci} in array {@code data}
@@ -62,7 +62,7 @@
 
     /**
      * Gets an unsigned 2-byte big-endian value.
-     * 
+     *
      * @param data the array containing the data
      * @param bci the start index of the value to retrieve
      * @return the unsigned 2-byte, big-endian, value at index {@code bci} in array {@code data}
@@ -73,7 +73,7 @@
 
     /**
      * Gets a signed 4-byte big-endian value.
-     * 
+     *
      * @param data the array containing the data
      * @param bci the start index of the value to retrieve
      * @return the signed 4-byte, big-endian, value at index {@code bci} in array {@code data}
@@ -84,7 +84,7 @@
 
     /**
      * Gets either a signed 2-byte or a signed 4-byte big-endian value.
-     * 
+     *
      * @param data the array containing the data
      * @param bci the start index of the value to retrieve
      * @param fourByte if true, this method will return a 4-byte value
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,24 +22,20 @@
  */
 package com.oracle.graal.compiler.common;
 
-import java.util.concurrent.*;
-
-public abstract class FieldIntrospection extends UnsafeAccess {
+public abstract class FieldIntrospection<T> extends UnsafeAccess {
 
-    protected static final ConcurrentHashMap<Class<?>, FieldIntrospection> allClasses = new ConcurrentHashMap<>();
-
-    private final Class<?> clazz;
+    private final Class<T> clazz;
 
     /**
      * The set of fields in {@link #clazz} that do long belong to a more specific category.
      */
     protected Fields data;
 
-    public FieldIntrospection(Class<?> clazz) {
+    public FieldIntrospection(Class<T> clazz) {
         this.clazz = clazz;
     }
 
-    public Class<?> getClazz() {
+    public Class<T> getClazz() {
         return clazz;
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,9 +30,6 @@
 // @formatter:off
 public final class GraalOptions {
 
-    @Option(help = "Use experimental baseline compiler configuration.", type = OptionType.Debug)
-    public static final OptionValue<Boolean> UseBaselineCompiler = new OptionValue<>(false);
-
     @Option(help = "Use compiler intrinsifications.", type = OptionType.Debug)
     public static final OptionValue<Boolean> Intrinsify = new OptionValue<>(true);
 
@@ -63,6 +60,9 @@
     @Option(help = "Inlines trivial methods during parsing of the bytecodes.", type = OptionType.Expert)
     public static final StableOptionValue<Boolean> InlineDuringParsing = new StableOptionValue<>(false);
 
+    @Option(help = "Traces .", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> TraceInlineDuringParsing = new StableOptionValue<>(false);
+
     @Option(help = "Maximum depth when inlining during parsing.", type = OptionType.Debug)
     public static final StableOptionValue<Integer> InlineDuringParsingMaxDepth = new StableOptionValue<>(10);
 
@@ -119,23 +119,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);
 
@@ -319,7 +307,7 @@
     public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionValue<Boolean> OptTailDuplication = new OptionValue<>(true);
+    public static final OptionValue<Boolean> OptTailDuplication = new OptionValue<>(false);
 
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
@@ -346,6 +334,9 @@
     @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)
     public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
 
+    @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)
+    public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
+
     /**
      * Counts the various paths taken through snippets.
      */
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IllegalStamp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -94,7 +94,7 @@
         throw GraalInternalError.shouldNotReachHere("can't read values of illegal stamp");
     }
 
-    private static IllegalStamp instance = new IllegalStamp();
+    private static final IllegalStamp instance = new IllegalStamp();
 
     static IllegalStamp getInstance() {
         return instance;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/VoidStamp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -112,7 +112,7 @@
         throw GraalInternalError.shouldNotReachHere("void stamp has no value");
     }
 
-    private static VoidStamp instance = new VoidStamp();
+    private static final VoidStamp instance = new VoidStamp();
 
     static VoidStamp getInstance() {
         return instance;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/ArrayMap.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/ArrayMap.java	Sat Feb 21 19:55:33 2015 +0100
@@ -45,7 +45,7 @@
     /**
      * Constructs a new {@code ArrayMap} that initially covers the specified interval. Note that
      * this map will automatically expand if necessary later.
-     * 
+     *
      * @param low the low index, inclusive
      * @param high the high index, exclusive
      */
@@ -56,7 +56,7 @@
 
     /**
      * Puts a new value in the map at the specified index.
-     * 
+     *
      * @param i the index at which to store the value
      * @param value the value to store at the specified index
      */
@@ -81,7 +81,7 @@
 
     /**
      * Gets the value at the specified index in the map.
-     * 
+     *
      * @param i the index
      * @return the value at the specified index; {@code null} if there is no value at the specified
      *         index, or if the index is out of the currently stored range
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/IntList.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/IntList.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,7 +26,7 @@
 
 /**
  * An expandable and indexable list of {@code int}s.
- * 
+ *
  * This class avoids the boxing/unboxing incurred by {@code ArrayList<Integer>}.
  */
 public final class IntList {
@@ -36,7 +36,7 @@
 
     /**
      * Creates an int list with a specified initial capacity.
-     * 
+     *
      * @param initialCapacity
      */
     public IntList(int initialCapacity) {
@@ -45,7 +45,7 @@
 
     /**
      * Creates an int list with a specified initial array.
-     * 
+     *
      * @param array the initial array used for the list (no copy is made)
      * @param initialSize the initial {@linkplain #size() size} of the list (must be less than or
      *            equal to {@code array.length}
@@ -58,7 +58,7 @@
 
     /**
      * Makes a new int list by copying a range from a given int list.
-     * 
+     *
      * @param other the list from which a range of values is to be copied into the new list
      * @param startIndex the index in {@code other} at which to start copying
      * @param length the number of values to copy from {@code other}
@@ -70,7 +70,7 @@
 
     /**
      * Makes a new int list by copying a range from a given int list.
-     * 
+     *
      * @param other the list from which a range of values is to be copied into the new list
      * @param startIndex the index in {@code other} at which to start copying
      * @param length the number of values to copy from {@code other}
@@ -91,7 +91,7 @@
 
     /**
      * Appends a value to the end of this list, increasing its {@linkplain #size() size} by 1.
-     * 
+     *
      * @param value the value to append
      */
     public void add(int value) {
@@ -104,7 +104,7 @@
 
     /**
      * Gets the value in this list at a given index.
-     * 
+     *
      * @param index the index of the element to return
      * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()}
      */
@@ -124,7 +124,7 @@
 
     /**
      * Sets a value at a given index in this list.
-     * 
+     *
      * @param index the index of the element to update
      * @param value the new value of the element
      * @throws IndexOutOfBoundsException if {@code index < 0 || index >= size()}
@@ -138,11 +138,11 @@
 
     /**
      * Adjusts the {@linkplain #size() size} of this int list.
-     * 
+     *
      * If {@code newSize < size()}, the size is changed to {@code newSize}. If
      * {@code newSize > size()}, sufficient 0 elements are {@linkplain #add(int) added} until
      * {@code size() == newSize}.
-     * 
+     *
      * @param newSize the new size of this int list
      */
     public void setSize(int newSize) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Sat Feb 21 19:55:33 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.*;
@@ -300,14 +300,13 @@
 
     final ValueNode getResult(String snippet) {
         processMethod(snippet);
-        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first().result();
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        return graph.getNodes(ReturnNode.TYPE).first().result();
     }
 
     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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Sat Feb 21 19:55:33 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);
@@ -132,8 +131,8 @@
         result = getResult(getCanonicalizedGraph("integerTestCanonicalization2"));
         assertTrue(result.isConstant() && result.asJavaConstant().asLong() == 1);
         StructuredGraph graph = getCanonicalizedGraph("integerTestCanonicalization3");
-        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
-        assertTrue(graph.getNodes(ReturnNode.class).first().result() instanceof ConditionalNode);
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        assertTrue(graph.getNodes(ReturnNode.TYPE).first().result() instanceof ConditionalNode);
     }
 
     public static int integerTestCanonicalization1(boolean b) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ConditionalEliminationTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/EliminateNestedCheckCastsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FloatingReadTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,7 +40,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.baseline.*;
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.GraalCompiler.Request;
 import com.oracle.graal.compiler.common.*;
@@ -50,11 +49,14 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+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.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.schedule.*;
@@ -69,7 +71,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>
@@ -87,7 +89,8 @@
 
     private final Providers providers;
     private final Backend backend;
-    private final Suites suites;
+    private final DerivedOptionValue<Suites> suites;
+    private final DerivedOptionValue<LIRSuites> lirSuites;
 
     /**
      * Can be overridden by unit tests to verify properties of the graph.
@@ -163,10 +166,16 @@
         return ret;
     }
 
+    protected LIRSuites createLIRSuites() {
+        LIRSuites ret = backend.getSuites().createLIRSuites();
+        return ret;
+    }
+
     public GraalCompilerTest() {
         this.backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
         this.providers = getBackend().getProviders();
-        this.suites = createSuites();
+        this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
         installSubstitutions();
     }
 
@@ -186,7 +195,8 @@
             this.backend = runtime.getHostBackend();
         }
         this.providers = backend.getProviders();
-        this.suites = createSuites();
+        this.suites = new DerivedOptionValue<>(this::createSuites);
+        this.lirSuites = new DerivedOptionValue<>(this::createLIRSuites);
         installSubstitutions();
     }
 
@@ -284,8 +294,8 @@
 
     protected void assertConstantReturn(StructuredGraph graph, int value) {
         String graphString = getCanonicalGraphString(graph, false, true);
-        Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.class).count(), 1);
-        ValueNode result = graph.getNodes(ReturnNode.class).first().result();
+        Assert.assertEquals("unexpected number of ReturnNodes: " + graphString, graph.getNodes(ReturnNode.TYPE).count(), 1);
+        ValueNode result = graph.getNodes(ReturnNode.TYPE).first().result();
         Assert.assertTrue("unexpected ReturnNode result node: " + graphString, result.isConstant());
         Assert.assertEquals("unexpected ReturnNode result kind: " + graphString, result.asJavaConstant().getKind(), Kind.Int);
         Assert.assertEquals("unexpected ReturnNode result: " + graphString, result.asJavaConstant().asInt(), value);
@@ -351,7 +361,11 @@
     }
 
     protected Suites getSuites() {
-        return suites;
+        return suites.getValue();
+    }
+
+    protected LIRSuites getLIRSuites() {
+        return lirSuites.getValue();
     }
 
     protected Providers getProviders() {
@@ -467,12 +481,7 @@
 
         checkArgs(method, executeArgs);
 
-        InstalledCode compiledMethod = null;
-        if (UseBaselineCompiler.getValue()) {
-            compiledMethod = getCodeBaseline(method);
-        } else {
-            compiledMethod = getCode(method);
-        }
+        InstalledCode compiledMethod = getCode(method);
         try {
             return new Result(compiledMethod.executeVarargs(executeArgs), null);
         } catch (Throwable e) {
@@ -482,73 +491,6 @@
         }
     }
 
-    protected InstalledCode getCodeBaseline(ResolvedJavaMethod javaMethod) {
-        return getCodeBaseline(javaMethod, false);
-    }
-
-    protected InstalledCode getCodeBaseline(ResolvedJavaMethod javaMethod, boolean forceCompile) {
-        assert javaMethod.getAnnotation(Test.class) == null : "shouldn't parse method with @Test annotation: " + javaMethod;
-
-        try (Scope bds = Debug.scope("Baseline")) {
-            Debug.log("getCodeBaseline()");
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        if (!forceCompile) {
-            InstalledCode cached = cache.get(javaMethod);
-            if (cached != null) {
-                if (cached.isValid()) {
-                    return cached;
-                }
-            }
-        }
-
-        final int id = compilationId.incrementAndGet();
-
-        InstalledCode installedCode = null;
-        try (Scope ds = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true))) {
-            final boolean printCompilation = PrintCompilation.getValue() && !TTY.isSuppressed();
-
-            if (printCompilation) {
-                TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s ...", id, javaMethod.getDeclaringClass().getName(), javaMethod.getName(), javaMethod.getSignature()));
-            }
-            long start = System.currentTimeMillis();
-
-            CompilationResult compResult = compileBaseline(javaMethod);
-
-            if (printCompilation) {
-                TTY.println(String.format("@%-6d Graal %-70s %-45s %-50s | %4dms %5dB", id, "", "", "", System.currentTimeMillis() - start, compResult.getTargetCodeSize()));
-            }
-
-            try (Scope s = Debug.scope("CodeInstall", getCodeCache(), javaMethod)) {
-                installedCode = addMethod(javaMethod, compResult);
-                if (installedCode == null) {
-                    throw new GraalInternalError("Could not install code for " + javaMethod.format("%H.%n(%p)"));
-                }
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
-        if (!forceCompile) {
-            cache.put(javaMethod, installedCode);
-        }
-        return installedCode;
-    }
-
-    private CompilationResult compileBaseline(ResolvedJavaMethod javaMethod) {
-        try (Scope bds = Debug.scope("CompileBaseline", javaMethod, providers.getCodeCache())) {
-            BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess());
-            OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
-            return baselineCompiler.generate(javaMethod, -1, getBackend(), new CompilationResult(), javaMethod, CompilationResultBuilderFactory.Default, optimisticOpts, getReplacements());
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-    }
-
     protected void checkArgs(ResolvedJavaMethod method, Object[] args) {
         JavaType[] sig = method.toParameterTypes();
         Assert.assertEquals(sig.length, args.length);
@@ -647,7 +589,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);
@@ -721,10 +663,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);
     }
 
     /**
@@ -740,7 +682,8 @@
         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(), new CompilationResult(), CompilationResultBuilderFactory.Default);
+                        OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), getLIRSuites(), new CompilationResult(),
+                        CompilationResultBuilderFactory.Default);
         return GraalCompiler.compile(request);
     }
 
@@ -800,16 +743,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);
     }
 
     /**
@@ -818,31 +761,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);
@@ -858,8 +801,9 @@
         PhaseSuite<HighTierContext> suite = getDefaultGraphBuilderSuite().copy();
         ListIterator<BasePhase<? super HighTierContext>> iterator = suite.findPhase(GraphBuilderPhase.class);
         GraphBuilderPhase graphBuilderPhase = (GraphBuilderPhase) iterator.previous();
+        GraphBuilderConfiguration gbConfCopy = gbConf.copy().copyPluginsFrom(graphBuilderPhase.getGraphBuilderConfig());
         iterator.remove();
-        iterator.add(new GraphBuilderPhase(gbConf, graphBuilderPhase.getGraphBuilderPlugins()));
+        iterator.add(new GraphBuilderPhase(gbConfCopy));
         return suite;
     }
 
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Sat Feb 21 19:55:33 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);
-        ParameterNode param = graph.getNodes(ParameterNode.class).iterator().next();
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        ParameterNode param = graph.getNodes(ParameterNode.TYPE).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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InfopointReasonTest.java	Sat Feb 21 19:55:33 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(), 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(), 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Sat Feb 21 19:55:33 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,9 +113,9 @@
     }
 
     private StructuredGraph getCanonicalizedGraph(String snippet) {
-        StructuredGraph graph = parseEager(snippet);
-        new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders(), null));
-        for (FrameState state : graph.getNodes(FrameState.class).snapshot()) {
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
+        new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders()));
+        for (FrameState state : graph.getNodes(FrameState.TYPE).snapshot()) {
             state.replaceAtUsages(null);
             state.safeDelete();
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LoopUnswitchTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Sat Feb 21 19:55:33 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.*;
@@ -264,8 +264,8 @@
     public void testArrayCopy() {
         SchedulePhase schedule = getFinalSchedule("testArrayCopySnippet", TestMode.INLINED_WITHOUT_FRAMESTATES);
         StructuredGraph graph = schedule.getCFG().getStartBlock().getBeginNode().graph();
-        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
-        ReturnNode ret = graph.getNodes(ReturnNode.class).first();
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        ReturnNode ret = graph.getNodes(ReturnNode.TYPE).first();
         assertTrue(ret.result() + " should be a FloatingReadNode", ret.result() instanceof FloatingReadNode);
         assertDeepEquals(schedule.getCFG().blockFor(ret), schedule.getCFG().blockFor(ret.result()));
         assertReadWithinAllReturnBlocks(schedule, true);
@@ -543,11 +543,11 @@
 
     private void assertReadWithinAllReturnBlocks(SchedulePhase schedule, boolean withinReturnBlock) {
         StructuredGraph graph = schedule.getCFG().graph;
-        assertTrue(graph.getNodes(ReturnNode.class).isNotEmpty());
+        assertTrue(graph.getNodes(ReturnNode.TYPE).isNotEmpty());
 
         int withRead = 0;
         int returnBlocks = 0;
-        for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) {
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
             Block block = schedule.getCFG().getNodeToBlock().get(returnNode);
             for (Node node : schedule.getBlockToNodesMap().get(block)) {
                 if (node instanceof FloatingReadNode) {
@@ -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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Sat Feb 21 19:55:33 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,10 +57,10 @@
     }
 
     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());
+        assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count());
     }
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Sat Feb 21 19:55:33 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.*;
@@ -69,7 +69,7 @@
     @Test
     public void test2() {
         StructuredGraph graph = parseAndProcess("test2Snippet");
-        NodeIterable<MonitorExitNode> monitors = graph.getNodes(MonitorExitNode.class);
+        NodeIterable<MonitorExitNode> monitors = graph.getNodes(MonitorExitNode.TYPE);
         Assert.assertEquals(1, monitors.count());
         Assert.assertEquals(monitors.first().stateAfter().bci, 3);
     }
@@ -84,8 +84,8 @@
     }
 
     private StructuredGraph parseAndProcess(String snippet) {
-        StructuredGraph graph = parseEager(snippet);
-        ParameterNode param = graph.getNodes(ParameterNode.class).first();
+        StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
+        ParameterNode param = graph.getNodes(ParameterNode.TYPE).first();
         if (param != null) {
             ConstantNode constant = ConstantNode.forInt(0, graph);
             for (Node n : param.usages().filter(isNotA(FrameState.class)).snapshot()) {
@@ -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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Sat Feb 21 19:55:33 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.*;
 
@@ -136,7 +137,7 @@
     }
 
     private static Invoke getInvoke(String name, StructuredGraph graph) {
-        for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
             if (callTarget.targetMethod().getName().equals(name)) {
                 return callTarget.invoke();
             }
@@ -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/NodePosIteratorTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,6 +33,7 @@
 
     @NodeInfo
     static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
         @Successor Node s1;
         @Successor Node s2;
         @Successor NodeSuccessorList<Node> stail;
@@ -42,6 +43,7 @@
         @Input FloatingNode i2;
 
         public TestNode() {
+            super(TYPE);
         }
 
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PhiCreationTests.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PhiCreationTests.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushNodesThroughPiTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushThroughIfTest.java	Sat Feb 21 19:55:33 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()) {
+        for (FrameState fs : graph.getNodes(FrameState.TYPE).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);
-        for (FrameState fs : referenceGraph.getNodes(FrameState.class).snapshot()) {
+        StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
+        for (FrameState fs : referenceGraph.getNodes(FrameState.TYPE).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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Sat Feb 21 19:55:33 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);
@@ -91,7 +91,7 @@
 
             Debug.dump(graph, "After lowering");
 
-            for (FloatingReadNode node : graph.getNodes(ParameterNode.class).first().usages().filter(FloatingReadNode.class)) {
+            for (FloatingReadNode node : graph.getNodes(ParameterNode.TYPE).first().usages().filter(FloatingReadNode.class)) {
                 // Checking that the parameter a is not directly used for the access to field
                 // x10 (because x10 must be guarded by the checkcast).
                 Assert.assertTrue(node.location().getLocationIdentity().isImmutable());
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReassociateAndCanonicalTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ScalarTypeSystemTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Sat Feb 21 19:55:33 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,10 +41,10 @@
 
     @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());
+        EndNode trueEnd = graph.add(new EndNode());
+        EndNode falseEnd = graph.add(new EndNode());
 
         AbstractBeginNode trueBegin = graph.add(new BeginNode());
         trueBegin.setNext(trueEnd);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StampCanonicalizerTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/StraighteningTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/TypeSystemTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/BackendTest.java	Sat Feb 21 19:55:33 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);
+        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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/CompiledMethodTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/deopt/MonitorDeoptTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Sat Feb 21 19:55:33 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,17 +149,16 @@
 
     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);
             new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true), null).apply(graph, context);
-            returnNodes = graph.getNodes(ReturnNode.class).snapshot();
+            returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Sat Feb 21 19:55:33 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.*;
@@ -79,13 +79,13 @@
 
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
-        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first();
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        return graph.getNodes(ReturnNode.TYPE).first();
     }
 
     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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Sat Feb 21 19:55:33 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.*;
@@ -199,7 +199,7 @@
     public void testPhi() {
         processMethod("testPhiSnippet");
         assertTrue(graph.getNodes().filter(LoadFieldNode.class).isEmpty());
-        List<ReturnNode> returnNodes = graph.getNodes(ReturnNode.class).snapshot();
+        List<ReturnNode> returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
         assertDeepEquals(2, returnNodes.size());
         assertTrue(returnNodes.get(0).predecessor() instanceof StoreFieldNode);
         assertTrue(returnNodes.get(1).predecessor() instanceof StoreFieldNode);
@@ -239,14 +239,13 @@
 
     final ReturnNode getReturn(String snippet) {
         processMethod(snippet);
-        assertDeepEquals(1, graph.getNodes(ReturnNode.class).count());
-        return graph.getNodes(ReturnNode.class).first();
+        assertDeepEquals(1, graph.getNodes(ReturnNode.TYPE).count());
+        return graph.getNodes(ReturnNode.TYPE).first();
     }
 
     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/PartialEscapeAnalysisTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -177,7 +177,7 @@
     @SafeVarargs
     protected final void testPartialEscapeAnalysis(final String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
         prepareGraph(snippet, false);
-        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.class)) {
+        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
             merge.setStateAfter(null);
         }
         new DeadCodeEliminationPhase().apply(graph);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Sat Feb 21 19:55:33 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,15 +59,14 @@
 
     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.
-            cleanup: for (FrameState fs : graph.getNodes(FrameState.class).snapshot()) {
+            cleanup: for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) {
                 for (Node input : fs.inputs()) {
                     if (input instanceof NewInstanceNode) {
                         fs.replaceAtUsages(null);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/InvokeGraal.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,7 +35,9 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 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.*;
@@ -77,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
@@ -94,6 +98,11 @@
             Suites suites = backend.getSuites().createSuites();
 
             /*
+             * The low-level phases that are applied to the low-level representation.
+             */
+            LIRSuites lirSuites = backend.getSuites().createLIRSuites();
+
+            /*
              * The calling convention for the machine code. You should have a very good reason
              * before you switch to a different calling convention than the one that the VM provides
              * by default.
@@ -117,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,
+            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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/tutorial/StaticAnalysis.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Sat Feb 21 19:55:33 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.*;
@@ -41,12 +40,13 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.alloc.lsra.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.lir.constopt.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.stackslotalloc.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
@@ -143,6 +143,7 @@
         public final ProfilingInfo profilingInfo;
         public final SpeculationLog speculationLog;
         public final Suites suites;
+        public final LIRSuites lirSuites;
         public final T compilationResult;
         public final CompilationResultBuilderFactory factory;
 
@@ -160,12 +161,13 @@
          * @param profilingInfo
          * @param speculationLog
          * @param suites
+         * @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, T compilationResult, CompilationResultBuilderFactory factory) {
+                        SpeculationLog speculationLog, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
             this.graph = graph;
             this.cc = cc;
             this.installedCodeOwner = installedCodeOwner;
@@ -178,6 +180,7 @@
             this.profilingInfo = profilingInfo;
             this.speculationLog = speculationLog;
             this.suites = suites;
+            this.lirSuites = lirSuites;
             this.compilationResult = compilationResult;
             this.factory = factory;
         }
@@ -203,9 +206,9 @@
      */
     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, T compilationResult, CompilationResultBuilderFactory factory) {
-        return compile(new Request<>(graph, cc, installedCodeOwner, providers, backend, target, cache, graphBuilderSuite, optimisticOpts, profilingInfo, speculationLog, suites, compilationResult,
-                        factory));
+                    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));
     }
 
     /**
@@ -216,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);
+            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);
         }
@@ -236,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);
@@ -254,15 +256,16 @@
             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();
 
             SchedulePhase schedule = new SchedulePhase();
+            schedule.setScheduleConstants(true);
             schedule.apply(graph);
             Debug.dump(schedule, "Final HIR schedule");
             return schedule;
@@ -272,12 +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) {
+                    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);
-            try (Scope s = Debug.scope("CodeGen", new Object[]{lirGen, lirGen.getLIR()})) {
-                emitCode(backend, assumptions, lirGen, compilationResult, installedCodeOwner, factory);
+            lirGen = emitLIR(backend, target, schedule, graph, stub, cc, registerConfig, lirSuites);
+            try (Scope s = Debug.scope("CodeGen", lirGen, lirGen.getLIR())) {
+                emitCode(backend, graph.getAssumptions(), graph.method(), graph.getInlinedMethods(), lirGen, compilationResult, installedCodeOwner, factory);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
@@ -297,7 +300,8 @@
         }
     }
 
-    public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc, RegisterConfig registerConfig) {
+    public static LIRGenerationResult emitLIR(Backend backend, TargetDescription target, SchedulePhase schedule, StructuredGraph graph, Object stub, CallingConvention cc,
+                    RegisterConfig registerConfig, LIRSuites lirSuites) {
         List<Block> blocks = schedule.getCFG().getBlocks();
         Block startBlock = schedule.getCFG().getStartBlock();
         assert startBlock != null;
@@ -336,67 +340,41 @@
                 throw Debug.handle(e);
             }
 
-            if (ConstantLoadOptimization.Options.ConstantLoadOptimization.getValue()) {
-                try (Scope s = Debug.scope("ConstantLoadOptimization", lir)) {
-                    ConstantLoadOptimization.optimize(lirGenRes.getLIR(), lirGen);
-                    Debug.dump(lir, "After constant load optimization");
-                } catch (Throwable e) {
-                    throw Debug.handle(e);
-                }
-            }
-
-            try (Scope s = Debug.scope("Allocator", nodeLirGen)) {
-                if (backend.shouldAllocateRegisters()) {
-                    LinearScan.allocate(target, lirGenRes);
-                }
+            try (Scope s = Debug.scope("LIRStages", nodeLirGen)) {
+                return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites);
             } catch (Throwable e) {
                 throw Debug.handle(e);
             }
-
-            try (Scope s1 = Debug.scope("BuildFrameMap")) {
-                // build frame map
-                final StackSlotAllocator allocator;
-                if (LSStackSlotAllocator.Options.LSStackSlotAllocation.getValue()) {
-                    allocator = new LSStackSlotAllocator();
-                } else {
-                    allocator = new SimpleStackSlotAllocator();
-                }
-                lirGenRes.buildFrameMap(allocator);
-                Debug.dump(lir, "After FrameMap building");
-            }
-            try (Scope s1 = Debug.scope("MarkLocations")) {
-                if (backend.shouldAllocateRegisters()) {
-                    // currently we mark locations only if we do register allocation
-                    LocationMarker.markLocations(lir, lirGenRes.getFrameMap());
-                }
-            }
-
-            try (Scope s = Debug.scope("ControlFlowOptimizations")) {
-                EdgeMoveOptimizer.optimize(lir);
-                ControlFlowOptimizer.optimize(lir, codeEmittingOrder);
-                if (lirGen.canEliminateRedundantMoves()) {
-                    RedundantMoveElimination.optimize(lir, frameMapBuilder);
-                }
-                NullCheckOptimizer.optimize(lir, target.implicitNullCheckLimit);
-
-                Debug.dump(lir, "After control flow optimization");
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-            return lirGenRes;
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
     }
 
-    public static void emitCode(Backend backend, Assumptions assumptions, LIRGenerationResult lirGenRes, CompilationResult compilationResult, ResolvedJavaMethod installedCodeOwner,
-                    CompilationResultBuilderFactory factory) {
+    public static <T extends AbstractBlock<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
+                    LIRGeneratorTool lirGen, LIRSuites lirSuites) {
+        PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
+        lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, preAllocOptContext);
+
+        AllocationContext allocContext = new AllocationContext();
+        lirSuites.getAllocationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, allocContext);
+
+        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext();
+        lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, postAllocOptContext);
+
+        return lirGenRes;
+    }
+
+    public static void emitCode(Backend backend, Assumptions assumptions, ResolvedJavaMethod rootMethod, Set<ResolvedJavaMethod> inlinedMethods, 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 (inlinedMethods != null) {
+            compilationResult.setMethods(rootMethod, inlinedMethods);
         }
 
         if (Debug.isMeterEnabled()) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalDebugConfig.java	Sat Feb 21 19:55:33 2015 +0100
@@ -65,6 +65,8 @@
     public static final OptionValue<Boolean> SuppressZeroDebugValues = new OptionValue<>(false);
     @Option(help = "Send Graal IR to dump handlers on error", type = OptionType.Debug)
     public static final OptionValue<Boolean> DumpOnError = new OptionValue<>(false);
+    @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
+    public static final OptionValue<Boolean> InterceptBailout = new OptionValue<>(false);
     @Option(help = "Enable more verbose log output when available", type = OptionType.Debug)
     public static final OptionValue<Boolean> LogVerbose = new OptionValue<>(false);
     // @formatter:on
@@ -254,7 +256,7 @@
 
     @Override
     public RuntimeException interceptException(Throwable e) {
-        if (e instanceof BailoutException) {
+        if (e instanceof BailoutException && !InterceptBailout.getValue()) {
             return null;
         }
         Debug.setConfig(Debug.fixedConfig(Debug.DEFAULT_LOG_LEVEL, Debug.DEFAULT_LOG_LEVEL, false, false, false, false, dumpHandlers, verifyHandlers, output));
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -98,7 +98,9 @@
                                 }
                             }
                             if (pos != vobj.entryCount()) {
-                                values = Arrays.copyOf(values, pos);
+                                JavaValue[] newValues = new JavaValue[pos];
+                                System.arraycopy(values, 0, newValues, 0, pos);
+                                values = newValues;
                             }
                         }
                         entry.getValue().setValues(values);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java	Sat Feb 21 19:55:33 2015 +0100
@@ -71,7 +71,7 @@
         /**
          * Prints this column's label to a given stream after padding the stream with '_' characters
          * until its {@linkplain LogStream#position() position} is equal to this column's position.
-         * 
+         *
          * @param out the print stream
          */
         public void printLabel(LogStream out) {
@@ -82,7 +82,7 @@
         /**
          * Prints space characters to a given stream until its {@linkplain LogStream#position()
          * position} is equal to this column's position.
-         * 
+         *
          * @param out the print stream
          */
         public void advance(LogStream out) {
@@ -116,7 +116,7 @@
     /**
      * Prints an instruction listing on one line. The instruction listing is composed of the columns
      * specified by {@link InstructionLineColumn}.
-     * 
+     *
      * @param instruction the instruction to print
      */
     public void printInstructionListing(ValueNode instruction) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -329,7 +329,7 @@
 
         gen.emitIncomingValues(params);
 
-        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
             Value paramValue = params[param.index()];
             assert paramValue.getLIRKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp()));
             setResult(param, gen.emitMove(paramValue));
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Sat Feb 21 19:55:33 2015 +0100
@@ -74,7 +74,7 @@
         }
     }
 
-    private static Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
+    private static final Pattern tokenizer = Pattern.compile("\\s*([()=]|[A-Za-z][A-Za-z0-9]*)\\s*");
 
     private class RuleParser {
         private ArrayList<TypeDescriptor> capturedTypes = new ArrayList<>();
@@ -455,7 +455,7 @@
         }
 
         String generatePositionDeclaration() {
-            return String.format("Position[] %s_positions = MatchRuleRegistry.findPositions(lookup, %s.class, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass,
+            return String.format("Position[] %s_positions = MatchRuleRegistry.findPositions(%s.TYPE, new String[]{\"%s\"});", nodeType.nodeClass, nodeType.nodeClass,
                             String.join("\", \"", nodeType.inputs));
         }
     }
@@ -535,7 +535,7 @@
             out.println("    }");
             out.println();
             out.println("    @Override");
-            out.println("    public List<" + desc + "> statements(MatchRuleRegistry.NodeClassLookup lookup) {");
+            out.println("    public List<" + desc + "> statements() {");
             out.println("        // Checkstyle: stop ");
 
             for (String positionDeclaration : info.positionDeclarations) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,32 +39,16 @@
 public class MatchRuleRegistry {
 
     /**
-     * Helper interface for mapping between Class and NodeClass. In static compilation environments,
-     * the current NodeClass might not be the same NodeClass used in the target so this provides a
-     * level of indirection.
-     */
-    public interface NodeClassLookup {
-        NodeClass get(Class<?> theClass);
-    }
-
-    static class DefaultNodeClassLookup implements NodeClassLookup {
-        public NodeClass get(Class<?> theClass) {
-            return NodeClass.get(theClass);
-        }
-    }
-
-    /**
      * Convert a list of field names into {@link com.oracle.graal.graph.Position} objects that can
      * be used to read them during a match. The names should already have been confirmed to exist in
      * the type.
      *
-     * @param theClass
+     * @param nodeClass
      * @param names
      * @return an array of Position objects corresponding to the named fields.
      */
-    public static Position[] findPositions(NodeClassLookup lookup, Class<? extends ValueNode> theClass, String[] names) {
+    public static Position[] findPositions(NodeClass<? extends ValueNode> nodeClass, String[] names) {
         Position[] result = new Position[names.length];
-        NodeClass nodeClass = lookup.get(theClass);
         for (int i = 0; i < names.length; i++) {
             Edges edges = nodeClass.getEdges(Inputs);
             for (int e = 0; e < edges.getDirectCount(); e++) {
@@ -73,7 +57,7 @@
                 }
             }
             if (result[i] == null) {
-                throw new GraalInternalError("unknown field \"%s\" in class %s", names[i], theClass);
+                throw new GraalInternalError("unknown field \"%s\" in class %s", names[i], nodeClass);
             }
         }
         return result;
@@ -91,8 +75,7 @@
         Map<Class<? extends ValueNode>, List<MatchStatement>> result = registry.get(theClass);
 
         if (result == null) {
-            NodeClassLookup lookup = new DefaultNodeClassLookup();
-            Map<Class<? extends ValueNode>, List<MatchStatement>> rules = createRules(theClass, lookup);
+            Map<Class<? extends ValueNode>, List<MatchStatement>> rules = createRules(theClass);
             registry.put(theClass, rules);
             assert registry.get(theClass) == rules;
             result = rules;
@@ -120,7 +103,7 @@
      * This is a separate, public method so that external clients can create rules with a custom
      * lookup and without the default caching behavior.
      */
-    public static Map<Class<? extends ValueNode>, List<MatchStatement>> createRules(Class<? extends NodeLIRBuilder> theClass, NodeClassLookup lookup) {
+    public static Map<Class<? extends ValueNode>, List<MatchStatement>> createRules(Class<? extends NodeLIRBuilder> theClass) {
         HashMap<Class<? extends NodeLIRBuilder>, MatchStatementSet> matchSets = new HashMap<>();
         Iterable<MatchStatementSet> sl = Services.load(MatchStatementSet.class);
         for (MatchStatementSet rules : sl) {
@@ -134,7 +117,7 @@
         do {
             MatchStatementSet matchSet = matchSets.get(currentClass);
             if (matchSet != null) {
-                List<MatchStatement> statements = matchSet.statements(lookup);
+                List<MatchStatement> statements = matchSet.statements();
                 for (MatchStatement statement : statements) {
                     Class<? extends ValueNode> nodeClass = statement.getPattern().nodeClass();
                     List<MatchStatement> current = rules.get(nodeClass);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,5 +37,5 @@
     /**
      * @return the {@link MatchStatement}s available for this {@link NodeLIRBuilder} subclass.
      */
-    List<MatchStatement> statements(MatchRuleRegistry.NodeClassLookup lookup);
+    List<MatchStatement> statements();
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,10 @@
 package com.oracle.graal.compiler.phases;
 
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.*;
+import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.*;
+import com.oracle.graal.lir.phases.AllocationPhase.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
@@ -40,4 +44,17 @@
     public PhaseSuite<LowTierContext> createLowTier() {
         return new LowTier();
     }
+
+    public LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage() {
+        return new PreAllocationOptimizationStage();
+    }
+
+    public LIRPhaseSuite<AllocationContext> createAllocationStage() {
+        return new AllocationStage();
+    }
+
+    public LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage() {
+        return new PostAllocationOptimizationStage();
+    }
+
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Sat Feb 21 19:55:33 2015 +0100
@@ -101,8 +101,6 @@
     public abstract CompilationResultBuilder newCompilationResultBuilder(LIRGenerationResult lirGenResult, FrameMap frameMap, CompilationResult compilationResult,
                     CompilationResultBuilderFactory factory);
 
-    public abstract boolean shouldAllocateRegisters();
-
     public abstract StackIntrospection getStackIntrospection();
 
     /**
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/Debug.java	Sat Feb 21 19:55:33 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);
     }
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfigScope.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfigScope.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,7 +27,7 @@
 /**
  * A utility for scoping a change to the current debug
  * {@linkplain DebugScope#setConfig(DebugConfig) configuration}. For example:
- * 
+ *
  * <pre>
  *     DebugConfig config = ...;
  *     try (DebugConfigScope s = new DebugConfigScope(config)) {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/LogStream.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/LogStream.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,20 +26,20 @@
 
 /**
  * A utility for printing compiler debug and informational output to an output stream.
- * 
+ *
  * A {@link LogStream} instance maintains an internal buffer that is flushed to the underlying
  * output stream every time one of the {@code println} methods is invoked, or a newline character (
  * {@code '\n'}) is written.
- * 
+ *
  * All of the {@code print} and {@code println} methods return the {code LogStream} instance on
  * which they were invoked. This allows chaining of these calls to mitigate use of String
  * concatenation by the caller.
- * 
+ *
  * A {@code LogStream} maintains a current {@linkplain #indentationLevel() indentation} level. Each
  * line of output written to this stream has {@code n} spaces prefixed to it where {@code n} is the
  * value that would be returned by {@link #indentationLevel()} when the first character of a new
  * line is written.
- * 
+ *
  * A {@code LogStream} maintains a current {@linkplain #position() position} for the current line
  * being written. This position can be advanced to a specified position by
  * {@linkplain #fillTo(int, char) filling} this stream with a given character.
@@ -87,7 +87,7 @@
 
     /**
      * Creates a new log stream.
-     * 
+     *
      * @param os the underlying output stream to which prints are sent
      */
     public LogStream(OutputStream os) {
@@ -98,7 +98,7 @@
     /**
      * Creates a new log stream that shares the same {@linkplain #ps output stream} as a given
      * {@link LogStream}.
-     * 
+     *
      * @param log a LogStream whose output stream is shared with this one
      */
     public LogStream(LogStream log) {
@@ -147,7 +147,7 @@
 
     /**
      * Gets the current column position of this log stream.
-     * 
+     *
      * @return the current column position of this log stream
      */
     public int position() {
@@ -157,7 +157,7 @@
 
     /**
      * Gets the current indentation level for this log stream.
-     * 
+     *
      * @return the current indentation level for this log stream.
      */
     public int indentationLevel() {
@@ -166,7 +166,7 @@
 
     /**
      * Adjusts the current indentation level of this log stream.
-     * 
+     *
      * @param delta
      */
     public void adjustIndentation(int delta) {
@@ -202,7 +202,7 @@
     /**
      * Advances this stream's {@linkplain #position() position} to a given position by repeatedly
      * appending a given character as necessary.
-     * 
+     *
      * @param position the position to which this stream's position will be advanced
      * @param filler the character used to pad the stream
      */
@@ -218,7 +218,7 @@
 
     /**
      * Writes a boolean value to this stream as {@code "true"} or {@code "false"}.
-     * 
+     *
      * @param b the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -233,7 +233,7 @@
     /**
      * Writes a boolean value to this stream followed by a {@linkplain #LINE_SEPARATOR line
      * separator}.
-     * 
+     *
      * @param b the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -248,7 +248,7 @@
 
     /**
      * Writes a character value to this stream.
-     * 
+     *
      * @param c the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -268,7 +268,7 @@
     /**
      * Writes a character value to this stream followed by a {@linkplain #LINE_SEPARATOR line
      * separator}.
-     * 
+     *
      * @param c the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -283,7 +283,7 @@
 
     /**
      * Prints an int value.
-     * 
+     *
      * @param i the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -297,7 +297,7 @@
 
     /**
      * Writes an int value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}.
-     * 
+     *
      * @param i the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -312,7 +312,7 @@
 
     /**
      * Writes a float value to this stream.
-     * 
+     *
      * @param f the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -327,7 +327,7 @@
     /**
      * Writes a float value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}
      * .
-     * 
+     *
      * @param f the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -342,7 +342,7 @@
 
     /**
      * Writes a long value to this stream.
-     * 
+     *
      * @param l the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -356,7 +356,7 @@
 
     /**
      * Writes a long value to this stream followed by a {@linkplain #LINE_SEPARATOR line separator}.
-     * 
+     *
      * @param l the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -371,7 +371,7 @@
 
     /**
      * Writes a double value to this stream.
-     * 
+     *
      * @param d the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -386,7 +386,7 @@
     /**
      * Writes a double value to this stream followed by a {@linkplain #LINE_SEPARATOR line
      * separator}.
-     * 
+     *
      * @param d the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -403,7 +403,7 @@
      * Writes a {@code String} value to this stream. This method ensures that the
      * {@linkplain #position() position} of this stream is updated correctly with respect to any
      * {@linkplain #LINE_SEPARATOR line separators} present in {@code s}.
-     * 
+     *
      * @param s the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -436,7 +436,7 @@
     /**
      * Writes a {@code String} value to this stream followed by a {@linkplain #LINE_SEPARATOR line
      * separator}.
-     * 
+     *
      * @param s the value to be printed
      * @return this {@link LogStream} instance
      */
@@ -450,7 +450,7 @@
 
     /**
      * Writes a formatted string to this stream.
-     * 
+     *
      * @param format a format string as described in {@link String#format(String, Object...)}
      * @param args the arguments to be formatted
      * @return this {@link LogStream} instance
@@ -464,7 +464,7 @@
 
     /**
      * Writes a {@linkplain #LINE_SEPARATOR line separator} to this stream.
-     * 
+     *
      * @return this {@code LogStream} instance
      */
     public LogStream println() {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Sat Feb 21 19:55:33 2015 +0100
@@ -46,7 +46,7 @@
          * Creates an object that will suppress {@link TTY} for the current thread if the given
          * filter does not match the given object. To revert the suppression state to how it was
          * before this call, the {@link #remove()} method must be called on the suppression object.
-         * 
+         *
          * @param filter the pattern for matching. If {@code null}, then the match is successful. If
          *            it starts with "~", then a regular expression
          *            {@linkplain Pattern#matches(String, CharSequence) match} is performed where
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValueMap.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValueMap.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,7 +29,7 @@
  */
 public class DebugValueMap {
 
-    private static List<DebugValueMap> topLevelMaps = new ArrayList<>();
+    private static final List<DebugValueMap> topLevelMaps = new ArrayList<>();
 
     private long[] values;
     private List<DebugValueMap> children;
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/KeyRegistry.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/KeyRegistry.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,12 +29,12 @@
  */
 public class KeyRegistry {
 
-    private static Map<String, Integer> keyMap = new HashMap<>();
-    private static List<DebugValue> debugValues = new ArrayList<>();
+    private static final Map<String, Integer> keyMap = new HashMap<>();
+    private static final List<DebugValue> debugValues = new ArrayList<>();
 
     /**
      * Ensures a given debug value is registered.
-     * 
+     *
      * @return the globally unique id for {@code value}
      */
     public static synchronized int register(DebugValue value) {
@@ -48,7 +48,7 @@
 
     /**
      * Gets a immutable view of the registered debug values.
-     * 
+     *
      * @return a list where {@code get(i).getIndex() == i}
      */
     public static synchronized List<DebugValue> getDebugValues() {
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Sat Feb 21 19:55:33 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
@@ -34,7 +34,10 @@
 
     @NodeInfo
     static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
         protected TestNode() {
+            super(TYPE);
         }
     }
 
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeUsagesTests.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeUsagesTests.java	Sat Feb 21 19:55:33 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
@@ -35,17 +35,22 @@
 
     @NodeInfo
     static final class Def extends Node {
+        public static final NodeClass<Def> TYPE = NodeClass.create(Def.class);
+
         protected Def() {
+            super(TYPE);
         }
     }
 
     @NodeInfo
     static final class Use extends Node {
+        public static final NodeClass<Use> TYPE = NodeClass.create(Use.class);
         @Input Def in0;
         @Input Def in1;
         @Input Def in2;
 
         public Use(Def in0, Def in1, Def in2) {
+            super(TYPE);
             this.in0 = in0;
             this.in1 = in1;
             this.in2 = in2;
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,11 +34,13 @@
 public class TypedNodeIteratorTest {
 
     @NodeInfo
-    static class TestNode extends Node implements IterableNodeType, TestNodeInterface {
+    static final class TestNode extends Node implements IterableNodeType, TestNodeInterface {
 
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
         protected final String name;
 
         public TestNode(String name) {
+            super(TYPE);
             this.name = name;
         }
 
@@ -51,8 +53,8 @@
     public void singleNodeTest() {
         Graph graph = new Graph();
         graph.add(new TestNode("a"));
-        assertTrue(graph.hasNode(TestNode.class));
-        assertEquals("a", toString(graph.getNodes(TestNode.class)));
+        assertTrue(graph.hasNode(TestNode.TYPE));
+        assertEquals("a", toString(graph.getNodes(TestNode.TYPE)));
     }
 
     @Test
@@ -61,7 +63,7 @@
         Graph graph = new Graph();
         graph.add(testNode);
         testNode.safeDelete();
-        assertEquals("", toString(graph.getNodes(TestNode.class)));
+        assertEquals("", toString(graph.getNodes(TestNode.TYPE)));
     }
 
     @Test
@@ -71,16 +73,16 @@
         graph.add(new TestNode("a"));
         graph.add(testNode);
         testNode.safeDelete();
-        assertEquals("a", toString(graph.getNodes(TestNode.class)));
+        assertEquals("a", toString(graph.getNodes(TestNode.TYPE)));
         graph.add(new TestNode("c"));
-        assertEquals("ac", toString(graph.getNodes(TestNode.class)));
+        assertEquals("ac", toString(graph.getNodes(TestNode.TYPE)));
     }
 
     @Test
     public void iteratorBehaviorTest() {
         Graph graph = new Graph();
         graph.add(new TestNode("a"));
-        Iterator<TestNode> iterator = graph.getNodes(TestNode.class).iterator();
+        Iterator<TestNode> iterator = graph.getNodes(TestNode.TYPE).iterator();
         assertTrue(iterator.hasNext());
         assertEquals("a", iterator.next().getName());
         assertFalse(iterator.hasNext());
@@ -99,7 +101,7 @@
     public void complicatedIterationTest() {
         Graph graph = new Graph();
         graph.add(new TestNode("a"));
-        for (TestNode tn : graph.getNodes(TestNode.class)) {
+        for (TestNode tn : graph.getNodes(TestNode.TYPE)) {
             String name = tn.getName();
             for (int i = 0; i < name.length(); ++i) {
                 char c = name.charAt(i);
@@ -119,7 +121,7 @@
                     graph.add(new TestNode("e"));
                     graph.add(new TestNode("d"));
                 } else if (c == 'd') {
-                    for (TestNode tn2 : graph.getNodes(TestNode.class)) {
+                    for (TestNode tn2 : graph.getNodes(TestNode.TYPE)) {
                         if (tn2.getName().equals("e")) {
                             tn2.safeDelete();
                         } else if (tn2.getName().equals("c")) {
@@ -131,7 +133,7 @@
                 }
             }
         }
-        assertEquals("dddd", toString(graph.getNodes(TestNode.class)));
+        assertEquals("dddd", toString(graph.getNodes(TestNode.TYPE)));
     }
 
     @Test
@@ -140,7 +142,7 @@
         graph.add(new TestNode("a"));
         StringBuilder sb = new StringBuilder();
         int z = 0;
-        for (TestNode tn : graph.getNodes(TestNode.class)) {
+        for (TestNode tn : graph.getNodes(TestNode.TYPE)) {
             if (z == 0) {
                 graph.add(new TestNode("b"));
             }
@@ -150,7 +152,7 @@
         assertEquals(2, z);
         assertEquals("ab", sb.toString());
         z = 0;
-        for (TestNode tn : graph.getNodes(TestNode.class)) {
+        for (TestNode tn : graph.getNodes(TestNode.TYPE)) {
             if (z == 0) {
                 graph.add(new TestNode("c"));
             }
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Sat Feb 21 19:55:33 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
@@ -34,9 +34,15 @@
     @NodeInfo
     static class NodeA extends Node implements TestNodeInterface {
 
+        public static final NodeClass<NodeA> TYPE = NodeClass.create(NodeA.class);
         protected final String name;
 
         public NodeA(String name) {
+            this(TYPE, name);
+        }
+
+        protected NodeA(NodeClass<? extends NodeA> c, String name) {
+            super(c);
             this.name = name;
         }
 
@@ -47,25 +53,38 @@
 
     @NodeInfo
     static class NodeB extends NodeA implements IterableNodeType {
+        public static final NodeClass<NodeB> TYPE = NodeClass.create(NodeB.class);
 
         public NodeB(String name) {
-            super(name);
+            this(TYPE, name);
+        }
+
+        protected NodeB(NodeClass<? extends NodeB> c, String name) {
+            super(c, name);
         }
 
     }
 
     @NodeInfo
     static class NodeC extends NodeB {
+        public static final NodeClass<NodeC> TYPE = NodeClass.create(NodeC.class);
+
         public NodeC(String name) {
-            super(name);
+            this(TYPE, name);
+        }
+
+        protected NodeC(NodeClass<? extends NodeC> c, String name) {
+            super(c, name);
         }
 
     }
 
     @NodeInfo
-    static class NodeD extends NodeC {
+    static final class NodeD extends NodeC {
+        public static final NodeClass<NodeD> TYPE = NodeClass.create(NodeD.class);
+
         public NodeD(String name) {
-            super(name);
+            super(TYPE, name);
         }
 
     }
@@ -76,8 +95,8 @@
         graph.add(new NodeB("b"));
         graph.add(new NodeD("d"));
 
-        Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.class)));
-        Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.class)));
+        Assert.assertEquals("bd", TypedNodeIteratorTest.toString(graph.getNodes(NodeB.TYPE)));
+        Assert.assertEquals("d", TypedNodeIteratorTest.toString(graph.getNodes(NodeD.TYPE)));
     }
 
     @Test
@@ -86,21 +105,21 @@
         graph.add(new NodeB("b1"));
         NodeD d1 = graph.add(new NodeD("d1"));
         StringBuilder sb = new StringBuilder();
-        for (NodeB tn : graph.getNodes(NodeB.class)) {
+        for (NodeB tn : graph.getNodes(NodeB.TYPE)) {
             if (tn == d1) {
                 graph.add(new NodeB("b2"));
             }
             sb.append(tn.getName());
         }
         assertEquals("b1d1b2", sb.toString());
-        for (NodeB tn : graph.getNodes(NodeB.class)) {
+        for (NodeB tn : graph.getNodes(NodeB.TYPE)) {
             if (tn == d1) {
                 graph.add(new NodeB("b3"));
             }
             assertNotNull(tn);
         }
-        assertEquals(4, graph.getNodes(NodeB.class).count());
-        assertEquals(1, graph.getNodes(NodeD.class).count());
+        assertEquals(4, graph.getNodes(NodeB.TYPE).count());
+        assertEquals(1, graph.getNodes(NodeD.TYPE).count());
     }
 
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Sat Feb 21 19:55:33 2015 +0100
@@ -485,7 +485,7 @@
     }
 
     public Node findDuplicate(Node node) {
-        NodeClass nodeClass = node.getNodeClass();
+        NodeClass<?> nodeClass = node.getNodeClass();
         assert nodeClass.valueNumberable();
         if (nodeClass.isLeafNode()) {
             // Leaf node: look up in cache
@@ -625,7 +625,11 @@
     // Fully qualified annotation name is required to satisfy javac
     @com.oracle.graal.nodeinfo.NodeInfo
     static final class PlaceHolderNode extends Node {
+
+        public static final NodeClass<PlaceHolderNode> TYPE = NodeClass.create(PlaceHolderNode.class);
+
         public PlaceHolderNode() {
+            super(TYPE);
         }
 
     }
@@ -685,11 +689,10 @@
      * Returns an {@link Iterable} providing all the live nodes whose type is compatible with
      * {@code type}.
      *
-     * @param type the type of node to return
+     * @param nodeClass the type of node to return
      * @return an {@link Iterable} providing all the matching nodes
      */
-    public <T extends Node & IterableNodeType> NodeIterable<T> getNodes(final Class<T> type) {
-        final NodeClass nodeClass = NodeClass.get(type);
+    public <T extends Node & IterableNodeType> NodeIterable<T> getNodes(final NodeClass<T> nodeClass) {
         return new NodeIterable<T>() {
 
             @Override
@@ -705,7 +708,7 @@
      * @param type the type of node that is checked for occurrence
      * @return whether there is at least one such node
      */
-    public <T extends Node & IterableNodeType> boolean hasNode(final Class<T> type) {
+    public <T extends Node & IterableNodeType> boolean hasNode(final NodeClass<T> type) {
         return getNodes(type).iterator().hasNext();
     }
 
@@ -738,7 +741,9 @@
         assert !isFrozen();
         assert node.id() == Node.INITIAL_ID;
         if (nodes.length == nodesSize) {
-            nodes = Arrays.copyOf(nodes, (nodesSize * 2) + 1);
+            Node[] newNodes = new Node[(nodesSize * 2) + 1];
+            System.arraycopy(nodes, 0, newNodes, 0, nodesSize);
+            nodes = newNodes;
         }
         int id = nodesSize;
         nodes[id] = node;
@@ -761,8 +766,9 @@
     }
 
     /**
-     * Rebuilds the lists used to support {@link #getNodes(Class)}. This is useful for serialization
-     * where the underlying {@linkplain NodeClass#iterableId() iterable ids} may have changed.
+     * Rebuilds the lists used to support {@link #getNodes(NodeClass)}. This is useful for
+     * serialization where the underlying {@linkplain NodeClass#iterableId() iterable ids} may have
+     * changed.
      */
     private void recomputeIterableNodeLists() {
         iterableNodesFirst.clear();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/IterableNodeType.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/IterableNodeType.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,7 +23,7 @@
 package com.oracle.graal.graph;
 
 /**
- * A marker for a node type supporting {@linkplain Graph#getNodes(Class) fast iteration} of its
+ * A marker for a node type supporting {@linkplain Graph#getNodes(NodeClass) fast iteration} of its
  * instances in a graph. The support for fast iteration comes with a memory cost (e.g., extra data
  * structures {@link Graph}) so only node types for which fast iteration provides a compilation
  * performance benefit should implement this interface.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sat Feb 21 19:55:33 2015 +0100
@@ -76,6 +76,7 @@
 @NodeInfo
 public abstract class Node implements Cloneable, Formattable {
 
+    public static final NodeClass<?> TYPE = null;
     public static final boolean USE_UNSAFE_TO_CLONE = Boolean.parseBoolean(System.getProperty("graal.node.useUnsafeToClone", "true"));
 
     static final int DELETED_ID_START = -1000000000;
@@ -160,6 +161,14 @@
          * ignored and can therefore safely be {@code null}.
          */
         boolean setStampFromReturnType() default false;
+
+        /**
+         * Determines if this intrinsic can be compile-time executed. An attempt to execute a call
+         * (via reflection) to this intrinsic at compile-time will be made if all of its arguments
+         * are compile-time constant. If the execution succeeds without an exception, the result is
+         * inserted as a constant node in the graph.
+         */
+        boolean foldable() default false;
     }
 
     /**
@@ -193,14 +202,15 @@
     int extraUsagesCount;
 
     private Node predecessor;
-    private NodeClass nodeClass;
+    private NodeClass<? extends Node> nodeClass;
 
     public static final int NODE_LIST = -2;
     public static final int NOT_ITERABLE = -1;
 
-    public Node() {
+    public Node(NodeClass<? extends Node> c) {
         init();
-        this.nodeClass = NodeClass.get(this.getClass());
+        assert c.getJavaClass() == this.getClass();
+        this.nodeClass = c;
     }
 
     final void init() {
@@ -332,7 +342,9 @@
             if (length == 0) {
                 extraUsages = new Node[4];
             } else if (extraUsagesCount == length) {
-                extraUsages = Arrays.copyOf(extraUsages, length * 2 + 1);
+                Node[] newExtraUsages = new Node[length * 2 + 1];
+                System.arraycopy(extraUsages, 0, newExtraUsages, 0, length);
+                extraUsages = newExtraUsages;
             }
             extraUsages[extraUsagesCount++] = node;
         }
@@ -497,7 +509,7 @@
         }
     }
 
-    public final NodeClass getNodeClass() {
+    public final NodeClass<? extends Node> getNodeClass() {
         return nodeClass;
     }
 
@@ -739,7 +751,7 @@
      * @return the copy of this node
      */
     final Node clone(Graph into, EnumSet<Edges.Type> edgesToCopy) {
-        final NodeClass nodeClassTmp = getNodeClass();
+        final NodeClass<? extends Node> nodeClassTmp = getNodeClass();
         boolean useIntoLeafNodeCache = false;
         if (into != null) {
             if (nodeClassTmp.valueNumberable() && nodeClassTmp.isLeafNode()) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,6 +30,7 @@
 import java.lang.annotation.*;
 import java.lang.reflect.*;
 import java.util.*;
+import java.util.concurrent.atomic.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
@@ -50,12 +51,9 @@
  * <li>The identifier for an {@link IterableNodeType} class.</li>
  * </ul>
  */
-public final class NodeClass extends FieldIntrospection {
-
-    private static final Object GetNodeClassLock = new Object();
+public final class NodeClass<T> extends FieldIntrospection<T> {
 
     // Timers for creation of a NodeClass instance
-    private static final DebugTimer Init = Debug.timer("NodeClass.Init");
     private static final DebugTimer Init_FieldScanning = Debug.timer("NodeClass.Init.FieldScanning");
     private static final DebugTimer Init_FieldScanningInner = Debug.timer("NodeClass.Init.FieldScanning.Inner");
     private static final DebugTimer Init_AnnotationParsing = Debug.timer("NodeClass.Init.AnnotationParsing");
@@ -73,45 +71,36 @@
     /**
      * Gets the {@link NodeClass} associated with a given {@link Class}.
      */
-    @SuppressWarnings("unchecked")
-    public static NodeClass get(Class<?> c) {
-        Class<? extends Node> key = (Class<? extends Node>) c;
+    public static <T> NodeClass<T> create(Class<T> c) {
+        assert get(c) == null;
+        Class<? super T> superclass = c.getSuperclass();
+        NodeClass<? super T> nodeSuperclass = null;
+        if (superclass != NODE_CLASS) {
+            nodeSuperclass = get(superclass);
+        }
+        return new NodeClass<>(c, nodeSuperclass);
+    }
 
-        NodeClass value = (NodeClass) allClasses.get(key);
-        // The fact that {@link ConcurrentHashMap#put} and {@link ConcurrentHashMap#get}
-        // are used makes the double-checked locking idiom work.
-        if (value == null) {
-            // The creation of a NodeClass must be serialized as the NodeClass constructor accesses
-            // both FieldIntrospection.allClasses and NodeClass.nextIterableId.
-            synchronized (GetNodeClassLock) {
-                try (TimerCloseable t = Init.start()) {
-                    value = (NodeClass) allClasses.get(key);
-                    if (value == null) {
-                        Class<?> superclass = c.getSuperclass();
-                        NodeClass superNodeClass = null;
-                        if (superclass != NODE_CLASS) {
-                            // Ensure NodeClass for superclass exists
-                            superNodeClass = get(superclass);
-                        }
-                        value = new NodeClass(key, superNodeClass);
-                        Object old = allClasses.putIfAbsent(key, value);
-                        assert old == null : old + "   " + key;
-                    }
-                }
-            }
+    @SuppressWarnings("unchecked")
+    public static <T> NodeClass<T> get(Class<T> superclass) {
+        try {
+            Field field = superclass.getDeclaredField("TYPE");
+            field.setAccessible(true);
+            return (NodeClass<T>) field.get(null);
+        } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
+            throw new RuntimeException(e);
         }
-        return value;
     }
 
     private static final Class<?> NODE_CLASS = Node.class;
     private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
     private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
 
-    private static int nextIterableId = 0;
+    private static AtomicInteger nextIterableId = new AtomicInteger();
 
     private final InputEdges inputs;
     private final SuccessorEdges successors;
-    private final NodeClass superNodeClass;
+    private final NodeClass<? super T> superNodeClass;
 
     private final boolean canGVN;
     private final int startGVNNumber;
@@ -134,11 +123,11 @@
     private final boolean isSimplifiable;
     private final boolean isLeafNode;
 
-    public NodeClass(Class<?> clazz, NodeClass superNodeClass) {
+    public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass) {
         this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0);
     }
 
-    public NodeClass(Class<?> clazz, NodeClass superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
+    public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
         super(clazz);
         this.superNodeClass = superNodeClass;
         assert NODE_CLASS.isAssignableFrom(clazz);
@@ -183,9 +172,9 @@
         } else if (IterableNodeType.class.isAssignableFrom(clazz)) {
             ITERABLE_NODE_TYPES.increment();
             try (TimerCloseable t1 = Init_IterableIds.start()) {
-                this.iterableId = nextIterableId++;
+                this.iterableId = nextIterableId.getAndIncrement();
 
-                NodeClass snc = superNodeClass;
+                NodeClass<?> snc = superNodeClass;
                 while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
                     assert !containsId(this.iterableId, snc.iterableIds);
                     snc.iterableIds = Arrays.copyOf(snc.iterableIds, snc.iterableIds.length + 1);
@@ -256,7 +245,7 @@
     }
 
     static int allocatedNodeIterabledIds() {
-        return nextIterableId;
+        return nextIterableId.get();
     }
 
     public EnumSet<InputType> getAllowedUsageTypes() {
@@ -316,7 +305,7 @@
         int directInputs;
         int directSuccessors;
 
-        protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass superNodeClass) {
+        protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass<?> superNodeClass) {
             super(calc);
             if (superNodeClass != null) {
                 translateInto(superNodeClass.inputs, inputs);
@@ -564,7 +553,7 @@
         return true;
     }
 
-    public boolean isValid(Position pos, NodeClass from, Edges fromEdges) {
+    public boolean isValid(Position pos, NodeClass<?> from, Edges fromEdges) {
         if (this == from) {
             return true;
         }
@@ -648,7 +637,7 @@
         }
     }
 
-    public Class<?> getJavaClass() {
+    public Class<T> getJavaClass() {
         return getClazz();
     }
 
@@ -702,7 +691,7 @@
         // re-wire inputs
         for (Node oldNode : nodes) {
             Node node = newNodes.get(oldNode);
-            NodeClass nodeClass = node.getNodeClass();
+            NodeClass<?> nodeClass = node.getNodeClass();
             if (replacements == null || replacements.replacement(oldNode) == oldNode) {
                 nodeClass.updateInputSuccInPlace(node, replacementClosure);
             } else {
@@ -746,8 +735,8 @@
     }
 
     private static void transferEdges(final Graph graph, final DuplicationReplacement replacements, final Map<Node, Node> newNodes, Node oldNode, Node node, Edges.Type type) {
-        NodeClass nodeClass = node.getNodeClass();
-        NodeClass oldNodeClass = oldNode.getNodeClass();
+        NodeClass<?> nodeClass = node.getNodeClass();
+        NodeClass<?> oldNodeClass = oldNode.getNodeClass();
         Edges oldEdges = oldNodeClass.getEdges(type);
         for (NodePosIterator oldIter = oldEdges.getIterable(oldNode).iterator(); oldIter.hasNext();) {
             Position pos = oldIter.nextPosition();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeIdAccessor.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeIdAccessor.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,7 +40,7 @@
 
     /**
      * Verifies that node identifiers have not changed since this object was created.
-     * 
+     *
      * @return true if the check succeeds
      * @throws VerificationError if the check fails
      */
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Sat Feb 21 19:55:33 2015 +0100
@@ -143,7 +143,9 @@
         if (length == 0) {
             nodes = new Node[2];
         } else if (size == length) {
-            nodes = Arrays.copyOf(nodes, nodes.length * 2 + 1);
+            Node[] newNodes = new Node[nodes.length * 2 + 1];
+            System.arraycopy(nodes, 0, newNodes, 0, length);
+            nodes = newNodes;
         }
         nodes[size++] = node;
         update(null, (T) node);
@@ -186,7 +188,9 @@
     void copy(NodeList<? extends Node> other) {
         self.incModCount();
         incModCount();
-        nodes = Arrays.copyOf(other.nodes, other.size);
+        Node[] newNodes = new Node[other.size];
+        System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length);
+        nodes = newNodes;
         size = other.size;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUnionFind.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,96 @@
+/*
+ * 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 (aRoot != bRoot) {
+            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/TypedGraphNodeIterator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/TypedGraphNodeIterator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,7 +33,7 @@
     private int currentIdIndex;
     private boolean needsForward;
 
-    public TypedGraphNodeIterator(NodeClass clazz, Graph graph) {
+    public TypedGraphNodeIterator(NodeClass<?> clazz, Graph graph) {
         this.graph = graph;
         ids = clazz.iterableIds();
         currentIdIndex = 0;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/VerificationError.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/VerificationError.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,7 +34,7 @@
      * This constructor creates a {@link VerificationError} with a message assembled via
      * {@link String#format(String, Object...)}. It always uses the ENGLISH locale in order to
      * always generate the same output.
-     * 
+     *
      * @param msg the message that will be associated with the error, in String.format syntax
      * @param args parameters to String.format - parameters that implement {@link Iterable} will be
      *            expanded into a [x, x, ...] representation.
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/CanonicalizerTool.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/CanonicalizerTool.java	Sat Feb 21 19:55:33 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.graph/src/com/oracle/graal/graph/spi/Simplifiable.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/Simplifiable.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,7 +25,7 @@
 /**
  * This interface allows nodes to perform more complicated simplifications, in contrast to
  * {@link Canonicalizable}, which supports only replacing the current node.
- * 
+ *
  * Implementors of this interface need to be aware that they need to call
  * {@link SimplifierTool#addToWorkList(com.oracle.graal.graph.Node)} for each node that might be
  * influenced (in terms of simplification and canonicalization) by the actions performed in
--- a/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/DataPatchInConstantsTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/DataPatchInConstantsTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.CompressionNode.CompressionOp;
@@ -154,11 +155,12 @@
 
     @NodeInfo
     private static final class LoadThroughPatchNode extends FixedWithNextNode implements LIRLowerable {
+        public static final NodeClass<LoadThroughPatchNode> TYPE = NodeClass.create(LoadThroughPatchNode.class);
 
         @Input protected ValueNode input;
 
         public LoadThroughPatchNode(ValueNode input) {
-            super(input.stamp());
+            super(TYPE, input.stamp());
             this.input = input;
         }
 
@@ -176,13 +178,15 @@
         public static native Object load(Object obj);
     }
 
-    private static class LoadThroughPatchOp extends LIRInstructionBase {
+    private static final class LoadThroughPatchOp extends LIRInstruction {
+        public static final LIRInstructionClass<LoadThroughPatchOp> TYPE = LIRInstructionClass.create(LoadThroughPatchOp.class);
 
         final Constant c;
         final boolean compressed;
         @Def({REG}) AllocatableValue result;
 
         LoadThroughPatchOp(Constant c, boolean compressed, AllocatableValue result) {
+            super(TYPE);
             this.c = c;
             this.compressed = compressed;
             this.result = result;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -32,10 +32,12 @@
 
 @Opcode("DEOPT")
 final class AMD64DeoptimizeOp extends AMD64LIRInstruction implements BlockEndOp {
+    public static final LIRInstructionClass<AMD64DeoptimizeOp> TYPE = LIRInstructionClass.create(AMD64DeoptimizeOp.class);
 
     @State private LIRFrameState info;
 
     AMD64DeoptimizeOp(LIRFrameState info) {
+        super(TYPE);
         this.info = info;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Sat Feb 21 19:55:33 2015 +0100
@@ -62,11 +62,6 @@
     }
 
     @Override
-    public boolean shouldAllocateRegisters() {
-        return true;
-    }
-
-    @Override
     public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
         RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
         return new AMD64FrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Sat Feb 21 19:55:33 2015 +0100
@@ -152,21 +152,18 @@
             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);
             }
             try (InitTimer rt = timer("create Suites provider")) {
-                suites = createSuites(runtime);
+                suites = createSuites(runtime, metaAccess, constantReflection, replacements);
             }
             providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
         }
@@ -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,
@@ -212,8 +209,8 @@
         return new HotSpotMetaAccessProvider(runtime);
     }
 
-    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime) {
-        return new HotSpotSuitesProvider(runtime);
+    protected HotSpotSuitesProvider createSuites(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
+        return new HotSpotSuitesProvider(runtime, metaAccess, constantReflection, replacements);
     }
 
     protected HotSpotSnippetReflectionProvider createSnippetReflection(HotSpotGraalRuntimeProvider runtime) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -30,12 +30,14 @@
 
 @Opcode("CRUNTIME_CALL_EPILOGUE")
 final class AMD64HotSpotCRuntimeCallEpilogueOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCRuntimeCallEpilogueOp.class);
 
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaFpOffset;
     private final Register thread;
 
     public AMD64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, Register thread) {
+        super(TYPE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaFpOffset = threadLastJavaFpOffset;
         this.thread = thread;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,11 +32,13 @@
 
 @Opcode
 final class AMD64HotSpotCRuntimeCallPrologueOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCRuntimeCallPrologueOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCRuntimeCallPrologueOp.class);
 
     private final int threadLastJavaSpOffset;
     private final Register thread;
 
     public AMD64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread) {
+        super(TYPE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.thread = thread;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java	Sat Feb 21 19:55:33 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
@@ -26,15 +26,18 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.hotspot.HotSpotGraalRuntime;
 
-public class AMD64HotSpotCardTableAddressOp extends AMD64LIRInstruction {
+public final class AMD64HotSpotCardTableAddressOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCardTableAddressOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCardTableAddressOp.class);
 
     @Def({OperandFlag.REG}) private AllocatableValue result;
 
     public AMD64HotSpotCardTableAddressOp(AllocatableValue result) {
+        super(TYPE);
         this.result = result;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java	Sat Feb 21 19:55:33 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
@@ -26,15 +26,18 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.hotspot.HotSpotGraalRuntime;
 
-public class AMD64HotSpotCardTableShiftOp extends AMD64LIRInstruction {
+public final class AMD64HotSpotCardTableShiftOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotCardTableShiftOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCardTableShiftOp.class);
 
     @Def({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue result;
 
     public AMD64HotSpotCardTableShiftOp(AllocatableValue result) {
+        super(TYPE);
         this.result = result;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -39,12 +39,14 @@
 public class AMD64HotSpotCompare {
 
     @Opcode("CMP")
-    public static class HotSpotCompareConstantOp extends AMD64LIRInstruction {
+    public static final class HotSpotCompareConstantOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<HotSpotCompareConstantOp> TYPE = LIRInstructionClass.create(HotSpotCompareConstantOp.class);
 
         @Use({REG}) protected AllocatableValue x;
         protected JavaConstant y;
 
         public HotSpotCompareConstantOp(AllocatableValue x, JavaConstant y) {
+            super(TYPE);
             this.x = x;
             this.y = y;
         }
@@ -100,12 +102,13 @@
     }
 
     @Opcode("CMP")
-    public static class HotSpotCompareMemoryConstantOp extends MemOp {
+    public static final class HotSpotCompareMemoryConstantOp extends MemOp {
+        public static final LIRInstructionClass<HotSpotCompareMemoryConstantOp> TYPE = LIRInstructionClass.create(HotSpotCompareMemoryConstantOp.class);
 
         protected JavaConstant y;
 
         public HotSpotCompareMemoryConstantOp(Kind kind, AMD64AddressValue x, JavaConstant y, LIRFrameState state) {
-            super(kind, x, state);
+            super(TYPE, kind, x, state);
             this.y = y;
         }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,6 +36,12 @@
 @Opcode("DEOPT_CALLER")
 final class AMD64HotSpotDeoptimizeCallerOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
+    public static final LIRInstructionClass<AMD64HotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(AMD64HotSpotDeoptimizeCallerOp.class);
+
+    protected AMD64HotSpotDeoptimizeCallerOp() {
+        super(TYPE);
+    }
+
     @Override
     public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
         leaveFrameAndRestoreRbp(crb, masm);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,6 +42,7 @@
  */
 @Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotEnterUnpackFramesStackFrameOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotEnterUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotEnterUnpackFramesStackFrameOp.class);
 
     private final Register threadRegister;
     private final int threadLastJavaSpOffset;
@@ -55,6 +56,7 @@
 
     AMD64HotSpotEnterUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, AllocatableValue framePc,
                     AllocatableValue senderSp, AllocatableValue senderFp, SaveRegistersOp saveRegisterOp) {
+        super(TYPE);
         this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,6 +38,10 @@
  */
 abstract class AMD64HotSpotEpilogueOp extends AMD64LIRInstruction {
 
+    protected AMD64HotSpotEpilogueOp(LIRInstructionClass<? extends AMD64HotSpotEpilogueOp> c) {
+        super(c);
+    }
+
     /**
      * The type of location (i.e., stack or register) in which RBP is saved is not known until
      * initial LIR generation is finished. Until then, we use a placeholder variable so that LIR
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.Options.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
@@ -61,8 +62,10 @@
         register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, null, exceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, exceptionCc, null, NOT_REEXECUTABLE, ANY_LOCATION));
 
-        link(new AMD64DeoptimizationStub(providers, target, config, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
-        link(new AMD64UncommonTrapStub(providers, target, config, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        if (PreferGraalStubs.getValue()) {
+            link(new AMD64DeoptimizationStub(providers, target, config, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+            link(new AMD64UncommonTrapStub(providers, target, config, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        }
 
         if (config.useCRC32Intrinsics) {
             // This stub does callee saving
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -41,6 +41,8 @@
 @Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
 final class AMD64HotSpotJumpToExceptionHandlerInCallerOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
+    public static final LIRInstructionClass<AMD64HotSpotJumpToExceptionHandlerInCallerOp> TYPE = LIRInstructionClass.create(AMD64HotSpotJumpToExceptionHandlerInCallerOp.class);
+
     @Use(REG) AllocatableValue handlerInCallerPc;
     @Use(REG) AllocatableValue exception;
     @Use(REG) AllocatableValue exceptionPc;
@@ -48,6 +50,7 @@
     private final int isMethodHandleReturnOffset;
 
     AMD64HotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) {
+        super(TYPE);
         this.handlerInCallerPc = handlerInCallerPc;
         this.exception = exception;
         this.exceptionPc = exceptionPc;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,9 +39,12 @@
 @Opcode("LEAVE_CURRENT_STACK_FRAME")
 final class AMD64HotSpotLeaveCurrentStackFrameOp extends AMD64HotSpotEpilogueOp {
 
+    public static final LIRInstructionClass<AMD64HotSpotLeaveCurrentStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveCurrentStackFrameOp.class);
+
     private final SaveRegistersOp saveRegisterOp;
 
     public AMD64HotSpotLeaveCurrentStackFrameOp(SaveRegistersOp saveRegisterOp) {
+        super(TYPE);
         this.saveRegisterOp = saveRegisterOp;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,10 +38,12 @@
 @Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
 final class AMD64HotSpotLeaveDeoptimizedStackFrameOp extends AMD64HotSpotEpilogueOp {
 
+    public static final LIRInstructionClass<AMD64HotSpotLeaveDeoptimizedStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveDeoptimizedStackFrameOp.class);
     @Use(REG) AllocatableValue frameSize;
     @Use(REG) AllocatableValue framePointer;
 
     public AMD64HotSpotLeaveDeoptimizedStackFrameOp(AllocatableValue frameSize, AllocatableValue initialInfo) {
+        super(TYPE);
         this.frameSize = frameSize;
         this.framePointer = initialInfo;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Sat Feb 21 19:55:33 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
@@ -38,6 +38,7 @@
  */
 @Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
 final class AMD64HotSpotLeaveUnpackFramesStackFrameOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotLeaveUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotLeaveUnpackFramesStackFrameOp.class);
 
     private final Register threadRegister;
     private final int threadLastJavaSpOffset;
@@ -47,6 +48,7 @@
     private final SaveRegistersOp saveRegisterOp;
 
     AMD64HotSpotLeaveUnpackFramesStackFrameOp(Register threadRegister, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, SaveRegistersOp saveRegisterOp) {
+        super(TYPE);
         this.threadRegister = threadRegister;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -43,12 +43,14 @@
 
 public class AMD64HotSpotMove {
 
-    public static class HotSpotLoadConstantOp extends AMD64LIRInstruction implements MoveOp {
+    public static final class HotSpotLoadConstantOp extends AMD64LIRInstruction implements MoveOp {
+        public static final LIRInstructionClass<HotSpotLoadConstantOp> TYPE = LIRInstructionClass.create(HotSpotLoadConstantOp.class);
 
         @Def({REG, STACK}) private AllocatableValue result;
         private final JavaConstant input;
 
         public HotSpotLoadConstantOp(AllocatableValue result, JavaConstant input) {
+            super(TYPE);
             this.result = result;
             this.input = input;
         }
@@ -145,9 +147,10 @@
     }
 
     public static class HotSpotStoreConstantOp extends StoreConstantOp {
+        public static final LIRInstructionClass<HotSpotStoreConstantOp> TYPE = LIRInstructionClass.create(HotSpotStoreConstantOp.class);
 
         public HotSpotStoreConstantOp(Kind kind, AMD64AddressValue address, JavaConstant input, LIRFrameState state) {
-            super(kind, address, input, state);
+            super(TYPE, kind, address, input, state);
         }
 
         @Override
@@ -181,7 +184,8 @@
         }
     }
 
-    public static class CompressPointer extends AMD64LIRInstruction {
+    public static final class CompressPointer extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
 
         private final CompressEncoding encoding;
         private final boolean nonNull;
@@ -191,6 +195,7 @@
         @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
 
         public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
             this.result = result;
             this.input = input;
             this.baseRegister = baseRegister;
@@ -218,7 +223,8 @@
         }
     }
 
-    public static class UncompressPointer extends AMD64LIRInstruction {
+    public static final class UncompressPointer extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
 
         private final CompressEncoding encoding;
         private final boolean nonNull;
@@ -228,6 +234,7 @@
         @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
 
         public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
+            super(TYPE);
             this.result = result;
             this.input = input;
             this.baseRegister = baseRegister;
@@ -274,12 +281,14 @@
         }
     }
 
-    public static class CompressedNullCheckOp extends AMD64LIRInstruction {
+    public static final class CompressedNullCheckOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompressedNullCheckOp> TYPE = LIRInstructionClass.create(CompressedNullCheckOp.class);
 
         @Use({COMPOSITE}) protected AMD64AddressValue address;
         @State protected LIRFrameState state;
 
         public CompressedNullCheckOp(AMD64AddressValue address, LIRFrameState state) {
+            super(TYPE);
             this.address = address;
             this.state = state;
         }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -134,7 +134,7 @@
         setSaveRbp(((AMD64HotSpotLIRGenerator) gen).new SaveRbp(new NoOp(gen.getCurrentBlock(), gen.getResult().getLIR().getLIRforBlock(gen.getCurrentBlock()).size())));
         append(getSaveRbp().placeholder);
 
-        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
             Value paramValue = params[param.index()];
             assert paramValue.getLIRKind().equals(getLIRGeneratorTool().getLIRKind(param.stamp()));
             setResult(param, gen.emitMove(paramValue));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -37,10 +37,12 @@
  */
 @Opcode("PATCH_RETURN")
 final class AMD64HotSpotPatchReturnAddressOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotPatchReturnAddressOp> TYPE = LIRInstructionClass.create(AMD64HotSpotPatchReturnAddressOp.class);
 
     @Use(REG) AllocatableValue address;
 
     AMD64HotSpotPatchReturnAddressOp(AllocatableValue address) {
+        super(TYPE);
         this.address = address;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,6 +39,7 @@
  */
 @Opcode("PUSH_INTERPRETER_FRAME")
 final class AMD64HotSpotPushInterpreterFrameOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotPushInterpreterFrameOp> TYPE = LIRInstructionClass.create(AMD64HotSpotPushInterpreterFrameOp.class);
 
     @Alive(REG) AllocatableValue frameSize;
     @Alive(REG) AllocatableValue framePc;
@@ -47,6 +48,7 @@
     private final HotSpotVMConfig config;
 
     AMD64HotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo, HotSpotVMConfig config) {
+        super(TYPE);
         this.frameSize = frameSize;
         this.framePc = framePc;
         this.senderSp = senderSp;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,12 +38,14 @@
 @Opcode("RETURN")
 final class AMD64HotSpotReturnOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
 
+    public static final LIRInstructionClass<AMD64HotSpotReturnOp> TYPE = LIRInstructionClass.create(AMD64HotSpotReturnOp.class);
     @Use({REG, ILLEGAL}) protected Value value;
     private final boolean isStub;
     private final Register scratchForSafepointOnReturn;
     private final HotSpotVMConfig config;
 
     AMD64HotSpotReturnOp(Value value, boolean isStub, Register scratchForSafepointOnReturn, HotSpotVMConfig config) {
+        super(TYPE);
         this.value = value;
         this.isStub = isStub;
         this.scratchForSafepointOnReturn = scratchForSafepointOnReturn;
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -40,7 +40,8 @@
  * Emits a safepoint poll.
  */
 @Opcode("SAFEPOINT")
-public class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
+public final class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64HotSpotSafepointOp> TYPE = LIRInstructionClass.create(AMD64HotSpotSafepointOp.class);
 
     @State protected LIRFrameState state;
     @Temp({OperandFlag.REG, OperandFlag.ILLEGAL}) private AllocatableValue temp;
@@ -48,6 +49,7 @@
     private final HotSpotVMConfig config;
 
     public AMD64HotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, NodeLIRBuilderTool tool) {
+        super(TYPE);
         this.state = state;
         this.config = config;
         if (isPollingPageFar(config) || ImmutableCode.getValue()) {
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,10 +40,12 @@
  */
 @Opcode("UNWIND")
 final class AMD64HotSpotUnwindOp extends AMD64HotSpotEpilogueOp implements BlockEndOp {
+    public static final LIRInstructionClass<AMD64HotSpotUnwindOp> TYPE = LIRInstructionClass.create(AMD64HotSpotUnwindOp.class);
 
     @Use({REG}) protected RegisterValue exception;
 
     AMD64HotSpotUnwindOp(RegisterValue exception) {
+        super(TYPE);
         this.exception = exception;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -36,11 +36,12 @@
  */
 @Opcode("CALL_DIRECT")
 final class AMD64HotspotDirectStaticCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<AMD64HotspotDirectStaticCallOp> TYPE = LIRInstructionClass.create(AMD64HotspotDirectStaticCallOp.class);
 
     private final InvokeKind invokeKind;
 
     AMD64HotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) {
-        super(target, result, parameters, temps, state);
+        super(TYPE, target, result, parameters, temps, state);
         assert invokeKind.isDirect();
         this.invokeKind = invokeKind;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,7 +28,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.HotSpotCodeCacheProvider.MarkId;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.AMD64Call.DirectCallOp;
+import com.oracle.graal.lir.amd64.AMD64Call.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 
@@ -38,12 +38,13 @@
  */
 @Opcode("CALL_DIRECT")
 final class AMD64HotspotDirectVirtualCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<AMD64HotspotDirectVirtualCallOp> TYPE = LIRInstructionClass.create(AMD64HotspotDirectVirtualCallOp.class);
 
     private final InvokeKind invokeKind;
     private final HotSpotVMConfig config;
 
     AMD64HotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
-        super(target, result, parameters, temps, state);
+        super(TYPE, target, result, parameters, temps, state);
         this.invokeKind = invokeKind;
         this.config = config;
         assert invokeKind.isIndirect();
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -43,6 +43,7 @@
  */
 @Opcode("CALL_INDIRECT")
 final class AMD64IndirectCallOp extends IndirectCallOp {
+    public static final LIRInstructionClass<AMD64IndirectCallOp> TYPE = LIRInstructionClass.create(AMD64IndirectCallOp.class);
 
     /**
      * Vtable stubs expect the metaspace Method in RBX.
@@ -52,7 +53,7 @@
     @Use({REG}) protected Value metaspaceMethod;
 
     AMD64IndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) {
-        super(targetMethod, result, parameters, temps, targetAddress, state);
+        super(TYPE, targetMethod, result, parameters, temps, targetAddress, state);
         this.metaspaceMethod = metaspaceMethod;
     }
 
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64PrefetchOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64PrefetchOp.java	Sat Feb 21 19:55:33 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
@@ -27,15 +27,18 @@
 
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.amd64.*;
 import com.oracle.graal.lir.asm.*;
 
-public class AMD64PrefetchOp extends AMD64LIRInstruction {
+public final class AMD64PrefetchOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64PrefetchOp> TYPE = LIRInstructionClass.create(AMD64PrefetchOp.class);
 
     private final int instr;  // AllocatePrefetchInstr
     @Alive({COMPOSITE}) protected AMD64AddressValue address;
 
     public AMD64PrefetchOp(AMD64AddressValue address, int instr) {
+        super(TYPE);
         this.address = address;
         this.instr = instr;
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,12 +34,13 @@
 
 @NodeInfo
 public final class AMD64RawNativeCallNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<AMD64RawNativeCallNode> TYPE = NodeClass.create(AMD64RawNativeCallNode.class);
 
     protected final JavaConstant functionPointer;
     @Input NodeInputList<ValueNode> args;
 
     public AMD64RawNativeCallNode(Kind returnType, JavaConstant functionPointer, ValueNode[] args) {
-        super(StampFactory.forKind(returnType));
+        super(TYPE, StampFactory.forKind(returnType));
         this.functionPointer = functionPointer;
         this.args = new NodeInputList<>(this, args);
     }
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64TailcallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64TailcallOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -36,12 +36,14 @@
  * {@link InstalledCode} instance.
  */
 @Opcode("TAILCALL")
-public class AMD64TailcallOp extends AMD64LIRInstruction {
+public final class AMD64TailcallOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64TailcallOp> TYPE = LIRInstructionClass.create(AMD64TailcallOp.class);
 
     @Use protected Value target;
     @Alive protected Value[] parameters;
 
     public AMD64TailcallOp(Value[] parameters, Value target) {
+        super(TYPE);
         this.target = target;
         this.parameters = parameters;
     }
--- a/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,7 +31,7 @@
 
 /**
  * A collection of java.lang.reflect proxies that communicate over a socket connection.
- * 
+ *
  * Calling a method sends the method name and the parameters through the socket. Afterwards this
  * class waits for a result. While waiting for a result three types of objects can arrive through
  * the socket: a method invocation, a method result or an exception. Method invocation can thus be
@@ -83,7 +83,7 @@
 
     /**
      * Represents one invocation of a method that is transferred via the socket connection.
-     * 
+     *
      */
     private static class Invocation implements Serializable {
 
@@ -102,7 +102,7 @@
 
     /**
      * Represents the result of an invocation that is transferred via the socket connection.
-     * 
+     *
      */
     private static class Result implements Serializable {
 
@@ -130,7 +130,7 @@
      * Each instance of this class handles remote invocations for one instance of a Remote class. It
      * will forward all interface methods to the other end of the socket and cache the results of
      * calls to certain methods.
-     * 
+     *
      */
     public class Handler implements InvocationHandler {
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -32,10 +32,12 @@
 
 @Opcode("DEOPT")
 final class SPARCDeoptimizeOp extends SPARCLIRInstruction implements BlockEndOp {
+    public static final LIRInstructionClass<SPARCDeoptimizeOp> TYPE = LIRInstructionClass.create(SPARCDeoptimizeOp.class);
 
     @State private LIRFrameState info;
 
     SPARCDeoptimizeOp(LIRFrameState info) {
+        super(TYPE);
         this.info = info;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Sat Feb 21 19:55:33 2015 +0100
@@ -68,11 +68,6 @@
     }
 
     @Override
-    public boolean shouldAllocateRegisters() {
-        return true;
-    }
-
-    @Override
     public FrameMapBuilder newFrameMapBuilder(RegisterConfig registerConfig) {
         RegisterConfig registerConfigNonNull = registerConfig == null ? getCodeCache().getRegisterConfig() : registerConfig;
         return new SPARCFrameMapBuilder(newFrameMap(registerConfigNonNull), getCodeCache(), registerConfigNonNull);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Sat Feb 21 19:55:33 2015 +0100
@@ -60,14 +60,11 @@
         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);
+        HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime, metaAccess, constantReflection, replacements);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
 
         return new SPARCHotSpotBackend(runtime, providers);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -36,6 +36,7 @@
 
 @Opcode("CRUNTIME_CALL_EPILOGUE")
 final class SPARCHotSpotCRuntimeCallEpilogueOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallEpilogueOp.class);
 
     private final int threadLastJavaSpOffset;
     private final int threadLastJavaPcOffset;
@@ -44,6 +45,7 @@
     @Use({REG, STACK}) protected Value threadTemp;
 
     public SPARCHotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset, Register thread, Value threadTemp) {
+        super(TYPE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
         this.threadJavaFrameAnchorFlagsOffset = threadJavaFrameAnchorFlagsOffset;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,6 +36,7 @@
 
 @Opcode("CRUNTIME_CALL_PROLOGUE")
 final class SPARCHotSpotCRuntimeCallPrologueOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotCRuntimeCallPrologueOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCRuntimeCallPrologueOp.class);
 
     private final int threadLastJavaSpOffset;
     private final Register thread;
@@ -43,6 +44,7 @@
     @Def({REG, STACK}) protected Value threadTemp;
 
     public SPARCHotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, Register thread, Register stackPointer, Value threadTemp) {
+        super(TYPE);
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.thread = thread;
         this.stackPointer = stackPointer;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,6 +36,11 @@
  */
 @Opcode("DEOPT_CALLER")
 final class SPARCHotSpotDeoptimizeCallerOp extends SPARCHotSpotEpilogueOp {
+    public static final LIRInstructionClass<SPARCHotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeCallerOp.class);
+
+    protected SPARCHotSpotDeoptimizeCallerOp() {
+        super(TYPE);
+    }
 
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Sat Feb 21 19:55:33 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
@@ -41,6 +41,7 @@
  */
 @Opcode("ENTER_UNPACK_FRAMES_STACK_FRAME")
 final class SPARCHotSpotEnterUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotEnterUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotEnterUnpackFramesStackFrameOp.class);
 
     private final Register thread;
     private final int threadLastJavaSpOffset;
@@ -50,6 +51,7 @@
     @Temp(REG) AllocatableValue scratch;
 
     SPARCHotSpotEnterUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue scratch) {
+        super(TYPE);
         this.thread = thread;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.sparc;
 
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
@@ -30,6 +31,11 @@
  * Superclass for operations that leave a method's frame.
  */
 abstract class SPARCHotSpotEpilogueOp extends SPARCLIRInstruction implements BlockEndOp {
+    public static final LIRInstructionClass<SPARCHotSpotEpilogueOp> TYPE = LIRInstructionClass.create(SPARCHotSpotEpilogueOp.class);
+
+    protected SPARCHotSpotEpilogueOp(LIRInstructionClass<? extends LIRInstruction> c) {
+        super(c);
+    }
 
     protected void leaveFrame(CompilationResultBuilder crb) {
         crb.frameContext.leave(crb);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.api.meta.Value.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.Options.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
@@ -61,8 +63,10 @@
         register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER, 0L, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
         register(new HotSpotForeignCallLinkageImpl(EXCEPTION_HANDLER_IN_CALLER, JUMP_ADDRESS, PRESERVES_REGISTERS, LEAF_NOFP, outgoingExceptionCc, incomingExceptionCc, NOT_REEXECUTABLE, ANY_LOCATION));
 
-        link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
-        link(new SPARCUncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        if (PreferGraalStubs.getValue()) {
+            link(new SPARCDeoptimizationStub(providers, target, registerStubCall(DEOPTIMIZATION_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+            link(new SPARCUncommonTrapStub(providers, target, registerStubCall(UNCOMMON_TRAP_HANDLER, REEXECUTABLE, LEAF, NO_LOCATIONS)));
+        }
 
         super.initialize(providers, config);
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -47,6 +47,8 @@
 @Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
 final class SPARCHotSpotJumpToExceptionHandlerInCallerOp extends SPARCHotSpotEpilogueOp {
 
+    public static final LIRInstructionClass<SPARCHotSpotDeoptimizeCallerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotDeoptimizeCallerOp.class);
+
     @Use(REG) AllocatableValue handlerInCallerPc;
     @Use(REG) AllocatableValue exception;
     @Use(REG) AllocatableValue exceptionPc;
@@ -54,6 +56,7 @@
     private final int isMethodHandleReturnOffset;
 
     SPARCHotSpotJumpToExceptionHandlerInCallerOp(AllocatableValue handlerInCallerPc, AllocatableValue exception, AllocatableValue exceptionPc, int isMethodHandleReturnOffset, Register thread) {
+        super(TYPE);
         this.handlerInCallerPc = handlerInCallerPc;
         this.exception = exception;
         this.exceptionPc = exceptionPc;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java	Sat Feb 21 19:55:33 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
@@ -35,8 +35,10 @@
  */
 @Opcode("LEAVE_CURRENT_STACK_FRAME")
 final class SPARCHotSpotLeaveCurrentStackFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotLeaveCurrentStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveCurrentStackFrameOp.class);
 
     public SPARCHotSpotLeaveCurrentStackFrameOp() {
+        super(TYPE);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java	Sat Feb 21 19:55:33 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
@@ -36,6 +36,12 @@
 @Opcode("LEAVE_DEOPTIMIZED_STACK_FRAME")
 final class SPARCHotSpotLeaveDeoptimizedStackFrameOp extends SPARCLIRInstruction {
 
+    public static final LIRInstructionClass<SPARCHotSpotLeaveDeoptimizedStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveDeoptimizedStackFrameOp.class);
+
+    protected SPARCHotSpotLeaveDeoptimizedStackFrameOp() {
+        super(TYPE);
+    }
+
     @Override
     public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
         // Save O registers over restore.
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java	Sat Feb 21 19:55:33 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
@@ -38,6 +38,7 @@
  */
 @Opcode("LEAVE_UNPACK_FRAMES_STACK_FRAME")
 final class SPARCHotSpotLeaveUnpackFramesStackFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotLeaveUnpackFramesStackFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotLeaveUnpackFramesStackFrameOp.class);
 
     private final Register thread;
     private final int threadLastJavaSpOffset;
@@ -45,6 +46,7 @@
     private final int threadJavaFrameAnchorFlagsOffset;
 
     SPARCHotSpotLeaveUnpackFramesStackFrameOp(Register thread, int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadJavaFrameAnchorFlagsOffset) {
+        super(TYPE);
         this.thread = thread;
         this.threadLastJavaSpOffset = threadLastJavaSpOffset;
         this.threadLastJavaPcOffset = threadLastJavaPcOffset;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -39,10 +39,12 @@
  */
 @Opcode("PATCH_RETURN")
 final class SPARCHotSpotPatchReturnAddressOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotPatchReturnAddressOp> TYPE = LIRInstructionClass.create(SPARCHotSpotPatchReturnAddressOp.class);
 
     @Use(REG) AllocatableValue address;
 
     SPARCHotSpotPatchReturnAddressOp(AllocatableValue address) {
+        super(TYPE);
         this.address = address;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
  */
 @Opcode("PUSH_INTERPRETER_FRAME")
 final class SPARCHotSpotPushInterpreterFrameOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotPushInterpreterFrameOp> TYPE = LIRInstructionClass.create(SPARCHotSpotPushInterpreterFrameOp.class);
 
     @Alive(REG) AllocatableValue frameSize;
     @Alive(REG) AllocatableValue framePc;
@@ -46,6 +47,7 @@
     @Alive(REG) AllocatableValue initialInfo;
 
     SPARCHotSpotPushInterpreterFrameOp(AllocatableValue frameSize, AllocatableValue framePc, AllocatableValue senderSp, AllocatableValue initialInfo) {
+        super(TYPE);
         this.frameSize = frameSize;
         this.framePc = framePc;
         this.senderSp = senderSp;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -37,12 +37,14 @@
  */
 @Opcode("RETURN")
 final class SPARCHotSpotReturnOp extends SPARCHotSpotEpilogueOp {
+    public static final LIRInstructionClass<SPARCHotSpotReturnOp> TYPE = LIRInstructionClass.create(SPARCHotSpotReturnOp.class);
 
     @Use({REG, ILLEGAL}) protected Value value;
     private final boolean isStub;
     private final HotSpotVMConfig config;
 
     SPARCHotSpotReturnOp(Value value, boolean isStub, HotSpotVMConfig config) {
+        super(TYPE);
         this.value = value;
         this.isStub = isStub;
         this.config = config;
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -43,6 +43,7 @@
  */
 @Opcode("SAFEPOINT")
 public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCHotSpotSafepointOp> TYPE = LIRInstructionClass.create(SPARCHotSpotSafepointOp.class);
 
     @State protected LIRFrameState state;
     @SuppressFBWarnings(value = "BC_IMPOSSIBLE_CAST", justification = "changed by the register allocator") @Temp({OperandFlag.REG}) private AllocatableValue temp;
@@ -50,9 +51,10 @@
     private final HotSpotVMConfig config;
 
     public SPARCHotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, LIRGeneratorTool tool) {
+        super(TYPE);
         this.state = state;
         this.config = config;
-        temp = tool.newVariable(LIRKind.value(tool.target().wordKind));
+        this.temp = tool.newVariable(LIRKind.value(tool.target().wordKind));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -41,10 +41,12 @@
  */
 @Opcode("UNWIND")
 final class SPARCHotSpotUnwindOp extends SPARCHotSpotEpilogueOp {
+    public static final LIRInstructionClass<SPARCHotSpotUnwindOp> TYPE = LIRInstructionClass.create(SPARCHotSpotUnwindOp.class);
 
     @Use({REG}) protected RegisterValue exception;
 
     SPARCHotSpotUnwindOp(RegisterValue exception) {
+        super(TYPE);
         this.exception = exception;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Sat Feb 21 19:55:33 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
@@ -36,11 +36,12 @@
  */
 @Opcode("CALL_DIRECT")
 final class SPARCHotspotDirectStaticCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<SPARCHotspotDirectStaticCallOp> TYPE = LIRInstructionClass.create(SPARCHotspotDirectStaticCallOp.class);
 
     private final InvokeKind invokeKind;
 
     SPARCHotspotDirectStaticCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind) {
-        super(target, result, parameters, temps, state);
+        super(TYPE, target, result, parameters, temps, state);
         assert invokeKind.isDirect();
         this.invokeKind = invokeKind;
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, 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
@@ -41,12 +41,13 @@
  */
 @Opcode("CALL_DIRECT")
 final class SPARCHotspotDirectVirtualCallOp extends DirectCallOp {
+    public static final LIRInstructionClass<SPARCHotspotDirectVirtualCallOp> TYPE = LIRInstructionClass.create(SPARCHotspotDirectVirtualCallOp.class);
 
     private final InvokeKind invokeKind;
     private final HotSpotVMConfig config;
 
     SPARCHotspotDirectVirtualCallOp(ResolvedJavaMethod target, Value result, Value[] parameters, Value[] temps, LIRFrameState state, InvokeKind invokeKind, HotSpotVMConfig config) {
-        super(target, result, parameters, temps, state);
+        super(TYPE, target, result, parameters, temps, state);
         this.invokeKind = invokeKind;
         this.config = config;
         assert invokeKind.isIndirect();
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -43,6 +43,7 @@
  */
 @Opcode("CALL_INDIRECT")
 final class SPARCIndirectCallOp extends IndirectCallOp {
+    public static final LIRInstructionClass<SPARCIndirectCallOp> TYPE = LIRInstructionClass.create(SPARCIndirectCallOp.class);
 
     /**
      * Vtable stubs expect the metaspace Method in g5.
@@ -52,7 +53,7 @@
     @Use({REG}) protected Value metaspaceMethod;
 
     SPARCIndirectCallOp(ResolvedJavaMethod targetMethod, Value result, Value[] parameters, Value[] temps, Value metaspaceMethod, Value targetAddress, LIRFrameState state) {
-        super(targetMethod, result, parameters, temps, targetAddress, state);
+        super(TYPE, targetMethod, result, parameters, temps, targetAddress, state);
         this.metaspaceMethod = metaspaceMethod;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,15 +27,18 @@
 
 import com.oracle.graal.asm.sparc.SPARCAssembler.Prefetch;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
 
-public class SPARCPrefetchOp extends SPARCLIRInstruction {
+public final class SPARCPrefetchOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCPrefetchOp> TYPE = LIRInstructionClass.create(SPARCPrefetchOp.class);
 
     private final int instr;  // AllocatePrefetchInstr
     @Alive({COMPOSITE}) protected SPARCAddressValue address;
 
     public SPARCPrefetchOp(SPARCAddressValue address, int instr) {
+        super(TYPE);
         this.address = address;
         this.instr = instr;
     }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,7 +39,9 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.type.*;
 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;
@@ -182,7 +184,7 @@
         StructuredGraph result = compile("getBoxedBoolean", true);
 
         assertDeepEquals(2, result.getNodes().filter(FloatingReadNode.class).count());
-        assertDeepEquals(1, result.getNodes(PiNode.class).count());
+        assertDeepEquals(1, result.getNodes(PiNode.TYPE).count());
         assertDeepEquals(1, getConstantNodes(result).count());
         ConstantNode constant = getConstantNodes(result).first();
         assertDeepEquals(Kind.Long, constant.getKind());
@@ -193,7 +195,7 @@
     public void testBoxedBoolean() {
         StructuredGraph result = compile("getBoxedBoolean", false);
         assertDeepEquals(0, result.getNodes().filter(FloatingReadNode.class).count());
-        assertDeepEquals(0, result.getNodes(PiNode.class).count());
+        assertDeepEquals(0, result.getNodes(PiNode.TYPE).count());
         assertDeepEquals(1, getConstantNodes(result).count());
         ConstantNode constant = getConstantNodes(result).first();
         assertDeepEquals(Kind.Object, constant.getKind());
@@ -203,15 +205,17 @@
     }
 
     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)) {
             CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graph.method(), false);
             // create suites everytime, as we modify options for the compiler
-            final Suites suitesLocal = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().createSuites();
+            SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
+            final Suites suitesLocal = suitesProvider.createSuites();
+            final LIRSuites lirSuitesLocal = suitesProvider.createLIRSuites();
             final CompilationResult compResult = compileGraph(graph, cc, method, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                            OptimisticOptimizations.ALL, getProfilingInfo(graph), getSpeculationLog(), suitesLocal, 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Sat Feb 21 19:55:33 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);
@@ -180,8 +181,8 @@
 
     private void testConstantReturn(String name, Object value) {
         StructuredGraph result = test(name);
-        ReturnNode ret = result.getNodes(ReturnNode.class).first();
-        assertDeepEquals(1, result.getNodes(ReturnNode.class).count());
+        ReturnNode ret = result.getNodes(ReturnNode.TYPE).first();
+        assertDeepEquals(1, result.getNodes(ReturnNode.TYPE).count());
 
         assertDeepEquals(true, ret.result().isConstant());
         assertDeepEquals(value, ret.result().asJavaConstant().asBoxedPrimitive());
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/DataPatchTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/DataPatchTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.nodes.CompressionNode.CompressionOp;
@@ -94,10 +95,11 @@
     @NodeInfo
     private static final class ConstantFoldBarrier extends FloatingNode implements LIRLowerable {
 
+        public static final NodeClass<ConstantFoldBarrier> TYPE = NodeClass.create(ConstantFoldBarrier.class);
         @Input protected ValueNode input;
 
         public ConstantFoldBarrier(ValueNode input) {
-            super(input.stamp());
+            super(TYPE, input.stamp());
             this.input = input;
         }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMethodSubstitutionTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -33,25 +33,20 @@
  */
 public class HotSpotMethodSubstitutionTest extends MethodSubstitutionTest {
 
-    /*
-     * We have to ignore this test for now because currently there is no way to read uncompressed
-     * pointers in a compressed world via JNI.
-     */
-    @Ignore
     @Test
     public void testObjectSubstitutions() {
+        TestClassA obj = new TestClassA();
+
         test("getClass0");
         test("objectHashCode");
 
-        Object obj = new Object();
-
-        assertDeepEquals("a string".getClass(), ObjectSubstitutions.getClass("a string"));
-        assertDeepEquals(obj.hashCode(), ObjectSubstitutions.hashCode(obj));
+        test("getClass0", "a string");
+        test("objectHashCode", obj);
     }
 
     @SuppressWarnings("all")
-    public static boolean getClass0(Object obj, Class<?> clazz) {
-        return obj.getClass() == clazz;
+    public static Class<?> getClass0(Object obj) {
+        return obj.getClass();
     }
 
     @SuppressWarnings("all")
@@ -59,15 +54,9 @@
         return obj.hashCode();
     }
 
-    /*
-     * We have to ignore this test for now because currently there is no way to read uncompressed
-     * pointers in a compressed world via JNI.
-     */
-    @Ignore
     @Test
     public void testClassSubstitutions() {
         test("getModifiers");
-        test("isInstance");
         test("isInterface");
         test("isArray");
         test("isPrimitive");
@@ -75,15 +64,12 @@
         test("getComponentType");
 
         for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
-            assertDeepEquals(c.getModifiers(), ClassSubstitutions.getModifiers(c));
-            assertDeepEquals(c.isInterface(), ClassSubstitutions.isInterface(c));
-            assertDeepEquals(c.isArray(), ClassSubstitutions.isArray(c));
-            assertDeepEquals(c.isPrimitive(), ClassSubstitutions.isPrimitive(c));
-            assertDeepEquals(c.getSuperclass(), ClassSubstitutions.getSuperclass(c));
-            assertDeepEquals(c.getComponentType(), ClassSubstitutions.getComponentType(c));
-            for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
-                assertDeepEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
-            }
+            test("getModifiers", c);
+            test("isInterface", c);
+            test("isArray", c);
+            test("isPrimitive", c);
+            test("getSuperClass", c);
+            test("getComponentType", c);
         }
     }
 
@@ -93,11 +79,6 @@
     }
 
     @SuppressWarnings("all")
-    public static boolean isInstance(Class<?> clazz) {
-        return clazz.isInstance(Number.class);
-    }
-
-    @SuppressWarnings("all")
     public static boolean isInterface(Class<?> clazz) {
         return clazz.isInterface();
     }
@@ -122,11 +103,6 @@
         return clazz.getComponentType();
     }
 
-    /*
-     * We have to ignore this test for now because currently there is no way to read uncompressed
-     * pointers in a compressed world via JNI.
-     */
-    @Ignore
     @Test
     public void testThreadSubstitutions() {
         test("currentThread");
@@ -134,13 +110,13 @@
         test("threadInterrupted");
 
         Thread currentThread = Thread.currentThread();
-        assertDeepEquals(currentThread, ThreadSubstitutions.currentThread());
-        assertDeepEquals(currentThread.isInterrupted(), ThreadSubstitutions.isInterrupted(currentThread, false));
+        test("currentThread", currentThread);
+        test("threadIsInterrupted", currentThread);
     }
 
     @SuppressWarnings("all")
-    public static Thread currentThread() {
-        return Thread.currentThread();
+    public static boolean currentThread(Thread other) {
+        return Thread.currentThread() == other;
     }
 
     @SuppressWarnings("all")
@@ -161,7 +137,7 @@
         SystemSubstitutions.currentTimeMillis();
         SystemSubstitutions.nanoTime();
         for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
-            assertDeepEquals(System.identityHashCode(o), SystemSubstitutions.identityHashCode(o));
+            test("systemIdentityHashCode", o);
         }
     }
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNmethodTest.java	Sat Feb 21 19:55:33 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/HotSpotNodeClassSubstitutionsTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.test;
-
-import org.junit.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.test.*;
-
-/**
- * Tests HotSpot specific substitutions for {@link NodeClass}.
- */
-public class HotSpotNodeClassSubstitutionsTest extends MethodSubstitutionTest {
-
-    @Test
-    public void test() {
-        test("get", ValueNode.class);
-    }
-
-    public static NodeClass get(Class<?> c) {
-        return NodeClass.get(c);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeSubstitutionsTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeSubstitutionsTest.java	Sat Feb 21 19:55:33 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,11 +36,11 @@
 
     @Test
     public void test() {
-        StructuredGraph graph = new StructuredGraph();
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.YES);
         test("getNodeClass", ConstantNode.forInt(42, graph));
     }
 
-    public static NodeClass getNodeClass(Node n) {
+    public static NodeClass<?> getNodeClass(Node n) {
         return n.getNodeClass();
     }
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/InstalledCodeExecuteHelperTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/MemoryUsageBenchmark.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Sat Feb 21 19:55:33 2015 +0100
@@ -42,7 +42,6 @@
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.baseline.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
@@ -53,8 +52,8 @@
 import com.oracle.graal.hotspot.events.EventProvider.CompilerFailureEvent;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.phases.*;
-import com.oracle.graal.java.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
@@ -96,17 +95,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;
     }
 
@@ -138,6 +136,10 @@
         return providers.getSuites().getDefaultSuites();
     }
 
+    protected LIRSuites getLIRSuites(HotSpotProviders providers) {
+        return providers.getSuites().getDefaultLIRSuites();
+    }
+
     protected PhaseSuite<HighTierContext> getGraphBuilderSuite(HotSpotProviders providers) {
         PhaseSuite<HighTierContext> suite = withSimpleDebugInfoIfRequested(providers.getSuites().getDefaultGraphBuilderSuite());
 
@@ -193,46 +195,45 @@
                 // Begin the compilation event.
                 compilationEvent.begin();
 
-                if (UseBaselineCompiler.getValue() == true) {
-                    HotSpotProviders providers = backend.getProviders();
-                    BaselineCompiler baselineCompiler = new BaselineCompiler(GraphBuilderConfiguration.getDefault(), providers.getMetaAccess());
-                    OptimisticOptimizations optimisticOpts = OptimisticOptimizations.ALL;
-                    result = baselineCompiler.generate(method, -1, backend, new CompilationResult(), method, CompilationResultBuilderFactory.Default, optimisticOpts, providers.getReplacements());
-                } else {
-                    Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
-                    if (GraalOptions.CacheGraphs.getValue()) {
-                        graphCache = new HashMap<>();
-                    }
+                Map<ResolvedJavaMethod, StructuredGraph> graphCache = null;
+                if (GraalOptions.CacheGraphs.getValue()) {
+                    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);
-                    } else {
-                        // Compiling method substitution - must clone the graph
-                        graph = graph.copy();
+                HotSpotProviders providers = backend.getProviders();
+                Replacements replacements = providers.getReplacements();
+                graph = replacements.getMethodSubstitution(method);
+                if (graph == null || entryBCI != INVOCATION_ENTRY_BCI) {
+                    graph = new StructuredGraph(method, entryBCI, AllowAssumptions.from(OptAssumptions.getValue()));
+                    if (!recordEvolMethodDeps) {
+                        graph.disableInlinedMethodRecording();
                     }
-                    InlinedBytecodes.add(method.getCodeSize());
-                    CallingConvention cc = getCallingConvention(providers.getCodeCache(), Type.JavaCallee, graph.method(), false);
-                    if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) {
-                        // for OSR, only a pointer is passed to the method.
-                        JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)};
-                        CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes,
-                                        backend.getTarget(), false);
-                        cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
-                    }
-                    Suites suites = getSuites(providers);
-                    ProfilingInfo profilingInfo = getProfilingInfo();
-                    OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
-                    if (isOSR) {
-                        // In OSR compiles, we cannot rely on never executed code profiles, because
-                        // all code after the OSR loop is never executed.
-                        optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
-                    }
-                    result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
-                                    method.getSpeculationLog(), suites, new CompilationResult(), CompilationResultBuilderFactory.Default);
+                } else {
+                    // Compiling method substitution - must clone the graph
+                    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);
+                if (graph.getEntryBCI() != StructuredGraph.INVOCATION_ENTRY_BCI) {
+                    // for OSR, only a pointer is passed to the method.
+                    JavaType[] parameterTypes = new JavaType[]{providers.getMetaAccess().lookupJavaType(long.class)};
+                    CallingConvention tmp = providers.getCodeCache().getRegisterConfig().getCallingConvention(JavaCallee, providers.getMetaAccess().lookupJavaType(void.class), parameterTypes,
+                                    backend.getTarget(), false);
+                    cc = new CallingConvention(cc.getStackSize(), cc.getReturn(), tmp.getArgument(0));
+                }
+                Suites suites = getSuites(providers);
+                LIRSuites lirSuites = getLIRSuites(providers);
+                ProfilingInfo profilingInfo = getProfilingInfo();
+                OptimisticOptimizations optimisticOpts = getOptimisticOpts(profilingInfo);
+                if (isOSR) {
+                    // In OSR compiles, we cannot rely on never executed code profiles, because
+                    // all code after the OSR loop is never executed.
+                    optimisticOpts.remove(Optimization.RemoveNeverExecutedCode);
+                }
+                result = compileGraph(graph, cc, method, providers, backend, backend.getTarget(), graphCache, getGraphBuilderSuite(providers), optimisticOpts, profilingInfo,
+                                method.getSpeculationLog(), suites, lirSuites, new CompilationResult(), CompilationResultBuilderFactory.Default);
                 result.setId(getId());
                 result.setEntryBCI(entryBCI);
             } catch (Throwable e) {
@@ -307,7 +308,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) {
@@ -329,7 +332,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);
         }
@@ -348,11 +351,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();
@@ -363,15 +366,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/HotSpotBackend.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Sat Feb 21 19:55:33 2015 +0100
@@ -42,6 +42,7 @@
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.options.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.word.*;
 
@@ -50,6 +51,13 @@
  */
 public abstract class HotSpotBackend extends Backend {
 
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Use Graal stubs instead of HotSpot stubs where possible")
+        public static final OptionValue<Boolean> PreferGraalStubs = new OptionValue<>(false);
+        // @formatter:on
+    }
+
     /**
      * Descriptor for {@link ExceptionHandlerStub}. This stub is called by the
      * {@linkplain HotSpotVMConfig#codeInstallerMarkIdExceptionHandlerEntry exception handler} in a
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,6 +25,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.hotspot.meta.*;
 
+import edu.umd.cs.findbugs.annotations.*;
+
 /**
  * {@link HotSpotCompiledCode} destined for installation as an nmethod.
  */
@@ -34,17 +36,32 @@
     public final HotSpotResolvedJavaMethod method;
     public final int entryBCI;
     public final int id;
-    public final long ctask;
+    public final long graalEnv;
+
+    /**
+     * May be set by VM if code installation fails. It will describe in more detail why installation
+     * failed (e.g., exactly which dependency failed).
+     */
+    @SuppressFBWarnings("UWF_UNWRITTEN_FIELD") private String installationFailureMessage;
 
     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 + "]";
+    }
+
+    public String getInstallationFailureMessage() {
+        return installationFailureMessage;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledRuntimeStub.java	Sat Feb 21 19:55:33 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() == null : "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/HotSpotDebugInfoBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -67,7 +67,7 @@
 
     @Override
     protected BytecodeFrame computeFrameForState(FrameState state) {
-        assert state.bci >= 0 || state.bci == BytecodeFrame.BEFORE_BCI;
+        assert state.bci >= 0 || state.bci == BytecodeFrame.BEFORE_BCI : state.bci;
         return super.computeFrameForState(state);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.replacements.*;
 
 /**
  * Common functionality of HotSpot host backends.
@@ -40,12 +41,16 @@
 public abstract class HotSpotHostBackend extends HotSpotBackend {
 
     /**
-     * Descriptor for {@link DeoptimizationStub#deoptimizationHandler}.
+     * Descriptor for {@code SharedRuntime::deopt_blob()->unpack()} or
+     * {@link DeoptimizationStub#deoptimizationHandler} depending on
+     * {@link HotSpotBackend.Options#PreferGraalStubs}.
      */
-    public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptimizationHandler", void.class);
+    public static final ForeignCallDescriptor DEOPTIMIZATION_HANDLER = new ForeignCallDescriptor("deoptHandler", void.class);
 
     /**
-     * Descriptor for {@link UncommonTrapStub#uncommonTrapHandler}.
+     * Descriptor for {@code SharedRuntime::deopt_blob()->uncommon_trap()} or
+     * {@link UncommonTrapStub#uncommonTrapHandler} depending on
+     * {@link HotSpotBackend.Options#PreferGraalStubs}.
      */
     public static final ForeignCallDescriptor UNCOMMON_TRAP_HANDLER = new ForeignCallDescriptor("uncommonTrapHandler", void.class);
 
@@ -68,11 +73,8 @@
 
         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);
-            }
+            InvocationPlugins plugins = phase.getGraphBuilderConfig().getInvocationPlugins();
+            registerInvocationPlugins(providers, plugins);
         }
 
         try (InitTimer st = timer("foreignCalls.initialize")) {
@@ -103,4 +105,9 @@
             }
         }
     }
+
+    protected void registerInvocationPlugins(HotSpotProviders providers, InvocationPlugins plugins) {
+        StandardGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), plugins);
+        HotSpotGraphBuilderPlugins.registerInvocationPlugins(providers, plugins);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Sat Feb 21 19:55:33 2015 +0100
@@ -898,7 +898,6 @@
     @HotSpotVMField(name = "Array<Klass*>::_length", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayLengthOffset;
     @HotSpotVMField(name = "Array<Klass*>::_data[0]", type = "Klass*", get = HotSpotVMField.Type.OFFSET) @Stable public int metaspaceArrayBaseOffset;
 
-    @HotSpotVMField(name = "InstanceKlass::_graal_node_class", type = "oop", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassNodeClassOffset;
     @HotSpotVMField(name = "InstanceKlass::_source_file_name_index", type = "u2", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassSourceFileNameIndexOffset;
     @HotSpotVMField(name = "InstanceKlass::_init_state", type = "u1", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassInitStateOffset;
     @HotSpotVMField(name = "InstanceKlass::_constants", type = "ConstantPool*", get = HotSpotVMField.Type.OFFSET) @Stable public int instanceKlassConstantsOffset;
@@ -1082,6 +1081,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;
 
     /**
@@ -1344,6 +1345,9 @@
     @HotSpotVMField(name = "CodeBlob::_code_offset", type = "int", get = HotSpotVMField.Type.OFFSET) @Stable private int codeBlobCodeOffsetOffset;
     @HotSpotVMField(name = "SharedRuntime::_ic_miss_blob", type = "RuntimeStub*", get = HotSpotVMField.Type.VALUE) @Stable private long inlineCacheMissBlob;
 
+    @HotSpotVMValue(expression = "SharedRuntime::deopt_blob()->unpack()", get = HotSpotVMValue.Type.ADDRESS) @Stable public long handleDeoptStub;
+    @HotSpotVMValue(expression = "SharedRuntime::deopt_blob()->uncommon_trap()", get = HotSpotVMValue.Type.ADDRESS) @Stable public long uncommonTrapStub;
+
     private final long inlineCacheMissStub;
 
     public long inlineCacheMissStub() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -387,13 +388,14 @@
     private static final LocationIdentity COUNTER_LOCATION = NamedLocationIdentity.mutable("COUNTER_LOCATION");
 
     @NodeInfo(nameTemplate = "CounterIndex")
-    private static class CounterIndexNode extends FloatingNode implements LIRLowerable {
+    private static final class CounterIndexNode extends FloatingNode implements LIRLowerable {
 
+        public static final NodeClass<CounterIndexNode> TYPE = NodeClass.create(CounterIndexNode.class);
         protected final Object counter;
         protected final int countersSize;
 
         protected CounterIndexNode(Stamp stamp, DynamicCounterNode counter, int countersSize) {
-            super(stamp);
+            super(TYPE, stamp);
             this.countersSize = countersSize;
             this.counter = counter;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -119,6 +119,10 @@
             if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
                 instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
             }
+        } else if (n instanceof ClassIsAssignableFromNode) {
+            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+                instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool);
+            }
         } else if (n instanceof NewInstanceNode) {
             if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
                 newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
@@ -352,7 +356,7 @@
 
             // mirroring the calculations in c1_GraphBuilder.cpp (setup_osr_entry_block)
             int localsOffset = (graph.method().getMaxLocals() - 1) * 8;
-            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.class)) {
+            for (OSRLocalNode osrLocal : graph.getNodes(OSRLocalNode.TYPE)) {
                 int size = osrLocal.getKind().getSlotCount();
                 int offset = localsOffset - (osrLocal.index() + size - 1) * 8;
                 IndexedLocationNode location = graph.unique(new IndexedLocationNode(ANY_LOCATION, offset, ConstantNode.forLong(0, graph), 1));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Sat Feb 21 19:55:33 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);
     }
 
@@ -259,8 +259,13 @@
             HotSpotInstalledCode code = new HotSpotNmethod(hotspotMethod, compResult.getName(), false);
             installedCode = code;
         }
-        CodeInstallResult result = runtime.getCompilerToVM().installCode(new HotSpotCompiledNmethod(hotspotMethod, compResult), installedCode, log);
+        HotSpotCompiledNmethod compiledCode = new HotSpotCompiledNmethod(hotspotMethod, compResult);
+        CodeInstallResult result = runtime.getCompilerToVM().installCode(compiledCode, installedCode, log);
         if (result != CodeInstallResult.OK) {
+            String msg = compiledCode.getInstallationFailureMessage();
+            if (msg != null) {
+                throw new BailoutException(result != CodeInstallResult.DEPENDENCIES_FAILED, "Code installation failed: %s%n%s", result, msg);
+            }
             throw new BailoutException(result != CodeInstallResult.DEPENDENCIES_FAILED, "Code installation failed: %s", result);
         }
         return logOrDump(installedCode, compResult);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Sat Feb 21 19:55:33 2015 +0100
@@ -119,9 +119,13 @@
      * Reference to the C++ ConstantPool object.
      */
     private final long metaspaceConstantPool;
+    private final Object[] cache;
+    private ResolvedJavaType lastType;
+    private int lastTypeCpi = Integer.MIN_VALUE;
 
     public HotSpotConstantPool(long metaspaceConstantPool) {
         this.metaspaceConstantPool = metaspaceConstantPool;
+        cache = new Object[length()];
     }
 
     /**
@@ -453,10 +457,20 @@
 
     @Override
     public JavaMethod lookupMethod(int cpi, int opcode) {
+        if (opcode != Bytecodes.INVOKEDYNAMIC) {
+            Object result = cache[cpi];
+            if (result != null) {
+                return (ResolvedJavaMethod) result;
+            }
+        }
         final int index = toConstantPoolIndex(cpi, opcode);
         final long metaspaceMethod = runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, index, (byte) opcode);
         if (metaspaceMethod != 0L) {
-            return HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod);
+            HotSpotResolvedJavaMethod result = HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod);
+            if (opcode != Bytecodes.INVOKEDYNAMIC) {
+                cache[cpi] = result;
+            }
+            return result;
         } else {
             // Get the method's name and signature.
             String name = getNameRefAt(index);
@@ -475,12 +489,24 @@
 
     @Override
     public JavaType lookupType(int cpi, int opcode) {
+        if (cpi == this.lastTypeCpi) {
+            return this.lastType;
+        }
         final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi);
-        return getJavaType(metaspacePointer);
+        JavaType result = getJavaType(metaspacePointer);
+        if (result instanceof ResolvedJavaType) {
+            this.lastType = (ResolvedJavaType) result;
+            this.lastTypeCpi = cpi;
+        }
+        return result;
     }
 
     @Override
     public JavaField lookupField(int cpi, int opcode) {
+        Object resolvedJavaField = cache[cpi];
+        if (resolvedJavaField != null) {
+            return (ResolvedJavaField) resolvedJavaField;
+        }
         final int index = toConstantPoolIndex(cpi, opcode);
         final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index);
         final int nameIndex = getNameRefIndexAt(nameAndTypeIndex);
@@ -507,7 +533,11 @@
             HotSpotResolvedObjectTypeImpl resolvedHolder = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass);
             final int flags = (int) info[0];
             final long offset = info[1];
-            return resolvedHolder.createField(name, type, offset, flags);
+            HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags);
+            if (type instanceof ResolvedJavaType) {
+                cache[cpi] = result;
+            }
+            return result;
         } else {
             return new HotSpotUnresolvedField(holder, name, type);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,253 @@
+/*
+ * 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.api.meta.LocationIdentity.*;
+import static com.oracle.graal.java.GraphBuilderContext.*;
+import static java.lang.Character.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.hotspot.nodes.type.*;
+import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
+import com.oracle.graal.java.InvocationPlugins.Registration;
+import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.HeapAccess.BarrierType;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.options.*;
+import com.oracle.graal.word.*;
+import com.oracle.graal.word.nodes.*;
+
+/**
+ * Provides HotSpot specific {@link InvocationPlugin}s.
+ */
+public class HotSpotGraphBuilderPlugins {
+    public static void registerInvocationPlugins(HotSpotProviders providers, InvocationPlugins plugins) {
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        SnippetReflectionProvider snippetReflection = providers.getSnippetReflection();
+        Kind wordKind = providers.getCodeCache().getTarget().wordKind;
+
+        registerObjectPlugins(plugins, metaAccess);
+        registerClassPlugins(plugins, metaAccess);
+        registerStableOptionPlugins(plugins, metaAccess);
+        registerMetaspacePointerPlugins(plugins, metaAccess, snippetReflection, wordKind);
+    }
+
+    private static void registerObjectPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
+        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;
+            }
+        });
+    }
+
+    private static void registerClassPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
+        Registration 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()) {
+                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
+                    if (type != null && !type.isPrimitive()) {
+                        builder.push(Kind.Object, builder.append(CheckCastNode.create(type, object, null, false, builder.getAssumptions())));
+                        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()) {
+                    ResolvedJavaType type = builder.getConstantReflection().asJavaType(rcvr.asConstant());
+                    if (type != null && !type.isPrimitive()) {
+                        LogicNode node = builder.append(InstanceOfNode.create(type, object, null));
+                        builder.push(Kind.Boolean.getStackKind(), builder.append(ConditionalNode.create(node)));
+                        return true;
+                    }
+                }
+                return false;
+            }
+        });
+    }
+
+    private static void registerStableOptionPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess) {
+        Registration 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;
+            }
+        });
+    }
+
+    private static void registerMetaspacePointerPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, Kind wordKind) {
+        Registration r = new Registration(plugins, metaAccess, MetaspacePointer.class);
+        r.register1("isNull", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode pointer) {
+                assert pointer.stamp() instanceof MetaspacePointerStamp;
+                IsNullNode isNull = builder.append(new IsNullNode(pointer));
+                ConstantNode trueValue = builder.append(ConstantNode.forBoolean(true));
+                ConstantNode falseValue = builder.append(ConstantNode.forBoolean(false));
+                builder.push(Kind.Boolean.getStackKind(), builder.append(new ConditionalNode(isNull, trueValue, falseValue)));
+                return true;
+            }
+        });
+        r.register1("asWord", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode pointer) {
+                builder.append(new PointerCastNode(StampFactory.forKind(wordKind), pointer));
+                return true;
+            }
+        });
+        r.register2("readObject", Receiver.class, int.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, int.class, LocationIdentity.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, int.class, BarrierType.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register2("readObject", Receiver.class, WordBase.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, WordBase.class, LocationIdentity.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+        r.register3("readObject", Receiver.class, WordBase.class, BarrierType.class, new ReadOp(snippetReflection, wordKind, Kind.Object, BarrierType.NONE, true));
+
+        registerWordOpPlugins(r, snippetReflection, wordKind, Kind.Byte, Kind.Short, Kind.Char, Kind.Int, Kind.Float, Kind.Long, Kind.Double);
+    }
+
+    private static void registerWordOpPlugins(Registration r, SnippetReflectionProvider snippetReflection, Kind wordKind, Kind... kinds) {
+        for (Kind kind : kinds) {
+            String kindName = kind.getJavaName();
+            kindName = toUpperCase(kindName.charAt(0)) + kindName.substring(1);
+            String getName = "read" + kindName;
+            // String putName = "write" + kindName;
+            r.register2(getName, Receiver.class, int.class, new ReadOp(snippetReflection, wordKind, kind));
+            r.register3(getName, Receiver.class, int.class, LocationIdentity.class, new ReadOp(snippetReflection, wordKind, kind));
+        }
+    }
+
+    static class ReadOp implements InvocationPlugin {
+        final SnippetReflectionProvider snippetReflection;
+        final Kind wordKind;
+        final Kind resultKind;
+        final BarrierType barrierType;
+        final boolean compressible;
+
+        public ReadOp(SnippetReflectionProvider snippetReflection, Kind wordKind, Kind resultKind, BarrierType barrierType, boolean compressible) {
+            this.snippetReflection = snippetReflection;
+            this.wordKind = wordKind;
+            this.resultKind = resultKind;
+            this.barrierType = barrierType;
+            this.compressible = compressible;
+        }
+
+        public ReadOp(SnippetReflectionProvider snippetReflection, Kind wordKind, Kind resultKind) {
+            this(snippetReflection, wordKind, resultKind, BarrierType.NONE, false);
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode pointer, ValueNode offset) {
+            LocationNode location = makeLocation(builder, offset, ANY_LOCATION, wordKind);
+            builder.push(resultKind, builder.append(readOp(builder, resultKind, pointer, location, barrierType, compressible)));
+            return true;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode pointer, ValueNode offset, ValueNode locationIdentityArg) {
+            assert locationIdentityArg.isConstant();
+            LocationIdentity locationIdentity = snippetReflection.asObject(LocationIdentity.class, locationIdentityArg.asJavaConstant());
+            LocationNode location = makeLocation(builder, offset, locationIdentity, wordKind);
+            builder.push(resultKind, builder.append(readOp(builder, resultKind, pointer, location, barrierType, compressible)));
+            return true;
+        }
+    }
+
+    public static ValueNode readOp(GraphBuilderContext builder, Kind readKind, ValueNode base, LocationNode location, BarrierType barrierType, boolean compressible) {
+        JavaReadNode read = builder.append(new JavaReadNode(readKind, base, location, barrierType, compressible));
+        /*
+         * The read must not float outside its block otherwise it may float above an explicit zero
+         * check on its base address.
+         */
+        read.setGuard(builder.getCurrentBlockGuard());
+        return read;
+    }
+
+    public static LocationNode makeLocation(GraphBuilderContext builder, ValueNode offset, LocationIdentity locationIdentity, Kind wordKind) {
+        return builder.append(new IndexedLocationNode(locationIdentity, 0, fromSigned(builder, offset, wordKind), 1));
+    }
+
+    public static LocationNode makeLocation(GraphBuilderContext builder, ValueNode offset, ValueNode locationIdentity, Kind wordKind) {
+        if (locationIdentity.isConstant()) {
+            return makeLocation(builder, offset, builder.getSnippetReflection().asObject(LocationIdentity.class, locationIdentity.asJavaConstant()), wordKind);
+        }
+        return builder.append(new SnippetLocationNode(builder.getSnippetReflection(), locationIdentity, builder.append(ConstantNode.forLong(0)), fromSigned(builder, offset, wordKind),
+                        builder.append(ConstantNode.forInt(1))));
+    }
+
+    public static ValueNode fromUnsigned(GraphBuilderContext builder, ValueNode value, Kind wordKind) {
+        return convert(builder, value, wordKind, true);
+    }
+
+    public static ValueNode fromSigned(GraphBuilderContext builder, ValueNode value, Kind wordKind) {
+        return convert(builder, value, wordKind, false);
+    }
+
+    public static ValueNode toUnsigned(GraphBuilderContext builder, ValueNode value, Kind toKind) {
+        return convert(builder, value, toKind, true);
+    }
+
+    public static ValueNode convert(GraphBuilderContext builder, ValueNode value, Kind toKind, boolean unsigned) {
+        if (value.getKind() == toKind) {
+            return value;
+        }
+
+        if (toKind == Kind.Int) {
+            assert value.getKind() == Kind.Long;
+            return builder.append(new NarrowNode(value, 32));
+        } else {
+            assert toKind == Kind.Long;
+            assert value.getKind().getStackKind() == Kind.Int;
+            if (unsigned) {
+                return builder.append(new ZeroExtendNode(value, 64));
+            } else {
+                return builder.append(new SignExtendNode(value, 64));
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,8 +25,10 @@
 import static com.oracle.graal.api.code.CallingConvention.Type.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.Options.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.RegisterEffect.*;
 import static com.oracle.graal.hotspot.HotSpotForeignCallLinkage.Transition.*;
+import static com.oracle.graal.hotspot.HotSpotHostBackend.*;
 import static com.oracle.graal.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.*;
 import static com.oracle.graal.hotspot.replacements.AssertionSnippets.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
@@ -138,6 +140,10 @@
     public void initialize(HotSpotProviders providers, HotSpotVMConfig c) {
         TargetDescription target = providers.getCodeCache().getTarget();
 
+        if (!PreferGraalStubs.getValue()) {
+            registerForeignCall(DEOPTIMIZATION_HANDLER, c.handleDeoptStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+            registerForeignCall(UNCOMMON_TRAP_HANDLER, c.uncommonTrapStub, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
+        }
         registerForeignCall(IC_MISS_HANDLER, c.inlineCacheMissStub(), NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
 
         registerForeignCall(JAVA_TIME_MILLIS, c.javaTimeMillisAddress, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, REEXECUTABLE, NO_LOCATIONS);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMemoryAccessProviderImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMemoryAccessProviderImpl.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
 
@@ -107,8 +106,6 @@
                     assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror();
                 } else if (displacement == runtime.getConfig().arrayKlassComponentMirrorOffset) {
                     assert expected == ((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror().getComponentType();
-                } else if (displacement == runtime.getConfig().instanceKlassNodeClassOffset) {
-                    assert expected == NodeClass.get(((HotSpotResolvedObjectTypeImpl) metaspaceObject).mirror());
                 }
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,7 +26,6 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
-import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.*;
 
 /**
@@ -70,12 +69,9 @@
         }
 
         public static Tag getEnum(int value) {
-            for (Tag e : values()) {
-                if (e.value == value) {
-                    return e;
-                }
-            }
-            throw GraalInternalError.shouldNotReachHere("unknown enum value " + value);
+            Tag result = values()[value];
+            assert value == result.value;
+            return result;
         }
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,7 +27,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.*;
 
 /**
@@ -62,14 +61,6 @@
     int getIdentityHashCode();
 
     /**
-     * Gets the result of {@link NodeClass#get(Class)} for the {@link Class} object represented by
-     * this constant.
-     *
-     * @return {@code null} if this constant does not represent a {@link Class} object
-     */
-    JavaConstant getNodeClass();
-
-    /**
      * Gets the result of {@link Class#getComponentType()} for the {@link Class} object represented
      * by this constant.
      *
@@ -96,7 +87,7 @@
     JavaConstant getCallSiteTarget(Assumptions assumptions);
 
     /**
-     * Gets the result of {@link CompositeValueClass#get(Class)} for the {@link Class} object
+     * Gets the result of {@link CompositeValueClass#create(Class)} for the {@link Class} object
      * represented by this constant.
      *
      * @return {@code null} if this constant does not represent a {@link Class} object
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,7 +28,6 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.*;
 
@@ -157,13 +156,6 @@
         return System.identityHashCode(object);
     }
 
-    public JavaConstant getNodeClass() {
-        if (object instanceof Class) {
-            return HotSpotObjectConstantImpl.forObject(NodeClass.get((Class<?>) object));
-        }
-        return null;
-    }
-
     public JavaConstant getComponentType() {
         if (object instanceof Class) {
             return HotSpotObjectConstantImpl.forObject(((Class<?>) object).getComponentType());
@@ -183,7 +175,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));
@@ -198,7 +190,7 @@
         if (object instanceof Class) {
             Class<? extends CompositeValue> c = (Class<? extends CompositeValue>) object;
             assert CompositeValue.class.isAssignableFrom(c) : c;
-            return HotSpotObjectConstantImpl.forObject(CompositeValueClass.get(c));
+            return HotSpotObjectConstantImpl.forObject(CompositeValueClass.create(c));
         }
         return null;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Sat Feb 21 19:55:33 2015 +0100
@@ -511,7 +511,9 @@
         int count = sig.getParameterCount(false);
         Class<?>[] result = new Class<?>[count];
         for (int i = 0; i < result.length; ++i) {
-            result[i] = ((HotSpotResolvedJavaType) sig.getParameterType(i, holder).resolve(holder)).mirror();
+            JavaType parameterType = sig.getParameterType(i, holder);
+            HotSpotResolvedJavaType resolvedParameterType = (HotSpotResolvedJavaType) parameterType.resolve(holder);
+            result[i] = resolvedParameterType.mirror();
         }
         return result;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Sat Feb 21 19:55:33 2015 +0100
@@ -118,13 +118,11 @@
         return Kind.fromTypeString(parameters.get(index));
     }
 
-    private static boolean checkValidCache(JavaType type, ResolvedJavaType accessingClass) {
+    private static boolean checkValidCache(ResolvedJavaType type, ResolvedJavaType accessingClass) {
         assert accessingClass != null;
-        if (!(type instanceof ResolvedJavaType)) {
+        if (type == null) {
             return false;
-        }
-
-        if (type instanceof HotSpotResolvedObjectTypeImpl) {
+        } else if (type instanceof HotSpotResolvedObjectTypeImpl) {
             return ((HotSpotResolvedObjectTypeImpl) type).isDefinitelyResolvedWithRespectTo(accessingClass);
         }
         return true;
@@ -151,8 +149,13 @@
 
         ResolvedJavaType type = parameterTypes[index];
         if (!checkValidCache(type, accessingClass)) {
-            type = (ResolvedJavaType) runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false);
-            parameterTypes[index] = type;
+            JavaType result = runtime.lookupType(parameters.get(index), (HotSpotResolvedObjectType) accessingClass, false);
+            if (result instanceof ResolvedJavaType) {
+                type = (ResolvedJavaType) result;
+                parameterTypes[index] = type;
+            } else {
+                return result;
+            }
         }
         return type;
     }
@@ -176,7 +179,12 @@
             return getUnresolvedOrPrimitiveType(runtime, returnType);
         }
         if (!checkValidCache(returnTypeCache, accessingClass)) {
-            returnTypeCache = (ResolvedJavaType) runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false);
+            JavaType result = runtime.lookupType(returnType, (HotSpotResolvedObjectType) accessingClass, false);
+            if (result instanceof ResolvedJavaType) {
+                returnTypeCache = (ResolvedJavaType) result;
+            } else {
+                return result;
+            }
         }
         return returnTypeCache;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,45 +22,73 @@
  */
 package com.oracle.graal.hotspot.meta;
 
+import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.replacements.NodeIntrinsificationPhase.*;
 
-import java.util.function.*;
+import java.util.*;
 
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.*;
 import com.oracle.graal.hotspot.phases.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderConfiguration.DebugInfoMode;
-import com.oracle.graal.java.GraphBuilderPlugins.InlineInvokePlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.AnnotatedInvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.options.*;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.replacements.*;
 
 /**
  * HotSpot implementation of {@link SuitesProvider}.
  */
-public class HotSpotSuitesProvider implements SuitesProvider, Supplier<Suites> {
+public class HotSpotSuitesProvider implements SuitesProvider {
 
     protected final DerivedOptionValue<Suites> defaultSuites;
     protected final PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
+    private final DerivedOptionValue<LIRSuites> defaultLIRSuites;
     protected final HotSpotGraalRuntimeProvider runtime;
 
-    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime) {
+    private class SuitesSupplier implements OptionSupplier<Suites> {
+
+        private static final long serialVersionUID = -3444304453553320390L;
+
+        public Suites get() {
+            return createSuites();
+        }
+
+    }
+
+    private class LIRSuitesSupplier implements OptionSupplier<LIRSuites> {
+
+        private static final long serialVersionUID = -1558586374095874299L;
+
+        public LIRSuites get() {
+            return createLIRSuites();
+        }
+
+    }
+
+    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
         this.runtime = runtime;
-        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
-        this.defaultSuites = new DerivedOptionValue<>(this);
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite(metaAccess, constantReflection, replacements);
+        this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
+        this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
 
     public Suites getDefaultSuites() {
         return defaultSuites.getValue();
     }
 
-    public Suites get() {
-        return createSuites();
-    }
-
     public PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite() {
         return defaultGraphBuilderSuite;
     }
@@ -84,15 +112,95 @@
         return ret;
     }
 
-    protected PhaseSuite<HighTierContext> createGraphBuilderSuite() {
+    NodeIntrinsificationPhase intrinsifier;
+
+    NodeIntrinsificationPhase getIntrinsifier() {
+        if (intrinsifier == null) {
+            HotSpotProviders providers = runtime.getHostProviders();
+            intrinsifier = new NodeIntrinsificationPhase(providers, providers.getSnippetReflection());
+        }
+        return intrinsifier;
+    }
+
+    MetaAccessProvider getMetaAccess() {
+        return runtime.getHostProviders().getMetaAccess();
+    }
+
+    protected PhaseSuite<HighTierContext> createGraphBuilderSuite(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
         PhaseSuite<HighTierContext> suite = new PhaseSuite<>();
         GraphBuilderConfiguration config = GraphBuilderConfiguration.getDefault();
-        config.setInlineInvokePlugin(new InlineInvokePlugin() {
-            public boolean shouldInlineInvoke(ResolvedJavaMethod method, int depth) {
-                return GraalOptions.InlineDuringParsing.getValue() && method.getCode().length <= GraalOptions.TrivialInliningSize.getValue() &&
-                                depth < GraalOptions.InlineDuringParsingMaxDepth.getValue();
-            }
-        });
+        if (InlineDuringParsing.getValue()) {
+            config.setLoadFieldPlugin(new LoadFieldPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+                    if (receiver.isConstant()) {
+                        JavaConstant asJavaConstant = receiver.asJavaConstant();
+                        return tryConstantFold(builder, metaAccess, constantReflection, field, asJavaConstant);
+                    }
+                    return false;
+                }
+
+                public boolean apply(GraphBuilderContext builder, ResolvedJavaField staticField) {
+                    return tryConstantFold(builder, metaAccess, constantReflection, staticField, null);
+                }
+            });
+            config.setInlineInvokePlugin(new InlineInvokePlugin() {
+                public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType, int depth) {
+                    ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
+                    if (subst != null) {
+                        return subst;
+                    }
+                    if (builder.parsingReplacement() && method.getAnnotation(NodeIntrinsic.class) == null) {
+                        return method;
+                    }
+                    if (method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && depth < InlineDuringParsingMaxDepth.getValue()) {
+                        return method;
+                    }
+                    return null;
+                }
+            });
+            config.setAnnotatedInvocationPlugin(new AnnotatedInvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args) {
+                    if (builder.parsingReplacement()) {
+                        @SuppressWarnings("hiding")
+                        NodeIntrinsificationPhase intrinsifier = getIntrinsifier();
+                        NodeIntrinsic intrinsic = intrinsifier.getIntrinsic(method);
+                        if (intrinsic != null) {
+                            Signature sig = method.getSignature();
+                            Kind returnKind = sig.getReturnKind();
+                            Stamp stamp = StampFactory.forKind(returnKind);
+                            if (returnKind == Kind.Object) {
+                                JavaType returnType = sig.getReturnType(method.getDeclaringClass());
+                                if (returnType instanceof ResolvedJavaType) {
+                                    stamp = StampFactory.declared((ResolvedJavaType) returnType);
+                                }
+                            }
+
+                            ValueNode res = intrinsifier.createIntrinsicNode(Arrays.asList(args), stamp, method, builder.getGraph(), intrinsic);
+                            res = builder.append(res);
+                            if (res.getKind().getStackKind() != Kind.Void) {
+                                builder.push(returnKind.getStackKind(), res);
+                            }
+                            return true;
+                        } else if (intrinsifier.isFoldable(method)) {
+                            ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
+                            JavaConstant constant = intrinsifier.tryFold(Arrays.asList(args), parameterTypes, method);
+                            if (!COULD_NOT_FOLD.equals(constant)) {
+                                if (constant != null) {
+                                    // Replace the invoke with the result of the call
+                                    ConstantNode res = builder.append(ConstantNode.forConstant(constant, getMetaAccess()));
+                                    builder.push(res.getKind().getStackKind(), builder.append(res));
+                                } else {
+                                    // This must be a void invoke
+                                    assert method.getSignature().getReturnKind() == Kind.Void;
+                                }
+                                return true;
+                            }
+                        }
+                    }
+                    return false;
+                }
+            });
+        }
         suite.appendPhase(new GraphBuilderPhase(config));
         return suite;
     }
@@ -117,4 +225,12 @@
         return gbs;
     }
 
+    public LIRSuites getDefaultLIRSuites() {
+        return defaultLIRSuites.getValue();
+    }
+
+    public LIRSuites createLIRSuites() {
+        return Suites.createDefaultLIRSuites();
+    }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/HotSpotNativeFunctionInterface.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,6 +37,7 @@
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
@@ -160,10 +161,11 @@
     private InstalledCode installNativeFunctionStub(long functionPointer, Class<?> returnType, Class<?>... argumentTypes) {
         StructuredGraph g = getGraph(providers, factory, functionPointer, returnType, argumentTypes);
         Suites suites = providers.getSuites().createSuites();
+        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, 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nfi/NativeCallStubGraphBuilder.java	Sat Feb 21 19:55:33 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/nodes/AllocaNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -38,6 +39,7 @@
 @NodeInfo
 public final class AllocaNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<AllocaNode> TYPE = NodeClass.create(AllocaNode.class);
     /**
      * The number of slots in block.
      */
@@ -51,7 +53,7 @@
     protected final BitSet objects;
 
     public AllocaNode(int slots, Kind wordKind, BitSet objects) {
-        super(StampFactory.forKind(wordKind));
+        super(TYPE, StampFactory.forKind(wordKind));
         this.slots = slots;
         this.objects = objects;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayRangeWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayRangeWriteBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,17 +22,19 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
 public abstract class ArrayRangeWriteBarrier extends WriteBarrier {
 
+    public static final NodeClass<ArrayRangeWriteBarrier> TYPE = NodeClass.create(ArrayRangeWriteBarrier.class);
     @Input ValueNode startIndex;
     @Input ValueNode length;
 
-    public ArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, null, null, true);
+    protected ArrayRangeWriteBarrier(NodeClass<? extends ArrayRangeWriteBarrier> c, ValueNode object, ValueNode startIndex, ValueNode length) {
+        super(c, object, null, null, true);
         this.startIndex = startIndex;
         this.length = length;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -40,10 +41,11 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class BeginLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorEnter, MemoryCheckpoint.Single {
 
+    public static final NodeClass<BeginLockScopeNode> TYPE = NodeClass.create(BeginLockScopeNode.class);
     protected int lockDepth;
 
     public BeginLockScopeNode(int lockDepth) {
-        super(null);
+        super(TYPE, null);
         this.lockDepth = lockDepth;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
@@ -34,10 +35,11 @@
 @NodeInfo
 public final class CStringNode extends FloatingNode implements LIRLowerable {
 
+    public static final NodeClass<CStringNode> TYPE = NodeClass.create(CStringNode.class);
     protected final String string;
 
     public CStringNode(String string) {
-        super(null);
+        super(TYPE, null);
         this.string = string;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.replacements.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,13 +34,15 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#cast(Object)}.
  *
- * @see ClassSubstitutions#cast(Class, Object)
+ * @see HotSpotClassSubstitutions#cast(Class, Object)
  */
 @NodeInfo
 public final class ClassCastNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
 
+    public static final NodeClass<ClassCastNode> TYPE = NodeClass.create(ClassCastNode.class);
+
     public ClassCastNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,14 +34,16 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#getClassLoader0()}.
  *
- * @see ClassSubstitutions#getClassLoader0(Class)
+ * @see HotSpotClassSubstitutions#getClassLoader0(Class)
  */
 @SuppressWarnings("javadoc")
 @NodeInfo
 public final class ClassGetClassLoader0Node extends MacroStateSplitNode implements Canonicalizable {
 
+    public static final NodeClass<ClassGetClassLoader0Node> TYPE = NodeClass.create(ClassGetClassLoader0Node.class);
+
     public ClassGetClassLoader0Node(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,13 +34,15 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#getComponentType()}.
  *
- * @see ClassSubstitutions#getComponentType(Class)
+ * @see HotSpotClassSubstitutions#getComponentType(Class)
  */
 @NodeInfo
 public final class ClassGetComponentTypeNode extends MacroNode implements Canonicalizable {
 
+    public static final NodeClass<ClassGetComponentTypeNode> TYPE = NodeClass.create(ClassGetComponentTypeNode.class);
+
     public ClassGetComponentTypeNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,13 +33,14 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#getModifiers()}.
  *
- * @see ClassSubstitutions#getModifiers(Class)
+ * @see HotSpotClassSubstitutions#getModifiers(Class)
  */
 @NodeInfo
 public final class ClassGetModifiersNode extends MacroNode implements Canonicalizable {
+    public static final NodeClass<ClassGetModifiersNode> TYPE = NodeClass.create(ClassGetModifiersNode.class);
 
     public ClassGetModifiersNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,13 +34,15 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#getSuperclass()}.
  *
- * @see ClassSubstitutions#getSuperclass(Class)
+ * @see HotSpotClassSubstitutions#getSuperclass(Class)
  */
 @NodeInfo
 public final class ClassGetSuperclassNode extends MacroNode implements Canonicalizable {
 
+    public static final NodeClass<ClassGetSuperclassNode> TYPE = NodeClass.create(ClassGetSuperclassNode.class);
+
     public ClassGetSuperclassNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,13 +33,15 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#isArray()}.
  *
- * @see ClassSubstitutions#isArray(Class)
+ * @see HotSpotClassSubstitutions#isArray(Class)
  */
 @NodeInfo
 public final class ClassIsArrayNode extends MacroNode implements Canonicalizable {
 
+    public static final NodeClass<ClassIsArrayNode> TYPE = NodeClass.create(ClassIsArrayNode.class);
+
     public ClassIsArrayNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsAssignableFromNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isAssignableFrom(Class)}.
- *
- * @see ClassSubstitutions#isAssignableFrom(Class, Class)
- */
-@NodeInfo
-public final class ClassIsAssignableFromNode extends MacroStateSplitNode implements Canonicalizable {
-    public ClassIsAssignableFromNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    private ValueNode getOtherClass() {
-        return arguments.get(1);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        ValueNode otherClass = getOtherClass();
-        if (javaClass.isConstant() && otherClass.isConstant()) {
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType thisType = constantReflection.asJavaType(javaClass.asJavaConstant());
-            ResolvedJavaType otherType = constantReflection.asJavaType(otherClass.asJavaConstant());
-            if (thisType != null && otherType != null) {
-                return ConstantNode.forBoolean(thisType.isAssignableFrom(otherType));
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInstanceNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.hotspot.nodes;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.replacements.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * {@link MacroNode Macro node} for {@link Class#isInstance(Object)}.
- *
- * @see ClassSubstitutions#isInstance(Class, Object)
- */
-@NodeInfo
-public final class ClassIsInstanceNode extends MacroNode implements Canonicalizable {
-
-    public ClassIsInstanceNode(Invoke invoke) {
-        super(invoke);
-    }
-
-    private ValueNode getJavaClass() {
-        return arguments.get(0);
-    }
-
-    private ValueNode getObject() {
-        return arguments.get(1);
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
-            ValueNode object = getObject();
-            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
-            ResolvedJavaType type = constantReflection.asJavaType(javaClass.asConstant());
-            if (type != null) {
-                if (type.isPrimitive()) {
-                    return ConstantNode.forBoolean(false);
-                }
-                if (object.isConstant()) {
-                    JavaConstant c = object.asJavaConstant();
-                    return ConstantNode.forBoolean(c.isNonNull() && type.isInstance(c));
-                }
-                InstanceOfNode instanceOf = new InstanceOfNode(type, object, null);
-                return new ConditionalNode(instanceOf, ConstantNode.forBoolean(true), ConstantNode.forBoolean(false));
-            }
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,13 +33,15 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#isInterface()}.
  *
- * @see ClassSubstitutions#isInterface(Class)
+ * @see HotSpotClassSubstitutions#isInterface(Class)
  */
 @NodeInfo
 public final class ClassIsInterfaceNode extends MacroNode implements Canonicalizable {
 
+    public static final NodeClass<ClassIsInterfaceNode> TYPE = NodeClass.create(ClassIsInterfaceNode.class);
+
     public ClassIsInterfaceNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,13 +33,15 @@
 /**
  * {@link MacroNode Macro node} for {@link Class#isPrimitive()}.
  *
- * @see ClassSubstitutions#isPrimitive(Class)
+ * @see HotSpotClassSubstitutions#isPrimitive(Class)
  */
 @NodeInfo
 public final class ClassIsPrimitiveNode extends MacroNode implements Canonicalizable {
 
+    public static final NodeClass<ClassIsPrimitiveNode> TYPE = NodeClass.create(ClassIsPrimitiveNode.class);
+
     public ClassIsPrimitiveNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getJavaClass() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
@@ -42,6 +43,8 @@
 @NodeInfo(nameTemplate = "{p#op/s}")
 public final class CompressionNode extends UnaryNode implements ConvertNode, LIRLowerable {
 
+    public static final NodeClass<CompressionNode> TYPE = NodeClass.create(CompressionNode.class);
+
     public enum CompressionOp {
         Compress,
         Uncompress
@@ -51,7 +54,7 @@
     protected final CompressEncoding encoding;
 
     public CompressionNode(CompressionOp op, ValueNode input, CompressEncoding encoding) {
-        super(mkStamp(op, input.stamp(), encoding), input);
+        super(TYPE, mkStamp(op, input.stamp(), encoding), input);
         this.op = op;
         this.encoding = encoding;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
@@ -39,11 +40,12 @@
  */
 @NodeInfo
 public final class CurrentJavaThreadNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<CurrentJavaThreadNode> TYPE = NodeClass.create(CurrentJavaThreadNode.class);
 
     protected LIRKind wordKind;
 
     public CurrentJavaThreadNode(Kind kind) {
-        super(StampFactory.forKind(kind));
+        super(TYPE, StampFactory.forKind(kind));
         this.wordKind = LIRKind.value(kind);
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -35,11 +36,12 @@
  */
 @NodeInfo
 public final class CurrentLockNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<CurrentLockNode> TYPE = NodeClass.create(CurrentLockNode.class);
 
     protected int lockDepth;
 
     public CurrentLockNode(int lockDepth) {
-        super(null);
+        super(TYPE, null);
         this.lockDepth = lockDepth;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
@@ -41,11 +42,12 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
 
+    public static final NodeClass<DeoptimizationFetchUnrollInfoCallNode> TYPE = NodeClass.create(DeoptimizationFetchUnrollInfoCallNode.class);
     @Input SaveAllRegistersNode registerSaver;
     protected final ForeignCallsProvider foreignCalls;
 
     public DeoptimizationFetchUnrollInfoCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver) {
-        super(StampFactory.forKind(Kind.fromJavaClass(FETCH_UNROLL_INFO.getResultType())));
+        super(TYPE, StampFactory.forKind(Kind.fromJavaClass(FETCH_UNROLL_INFO.getResultType())));
         this.registerSaver = (SaveAllRegistersNode) registerSaver;
         this.foreignCalls = foreignCalls;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -35,11 +36,12 @@
 @NodeInfo(shortName = "DeoptCaller", nameTemplate = "DeoptCaller {p#reason/s}")
 public final class DeoptimizeCallerNode extends ControlSinkNode implements LIRLowerable {
 
+    public static final NodeClass<DeoptimizeCallerNode> TYPE = NodeClass.create(DeoptimizeCallerNode.class);
     protected final DeoptimizationAction action;
     protected final DeoptimizationReason reason;
 
     public DeoptimizeCallerNode(DeoptimizationAction action, DeoptimizationReason reason) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.action = action;
         this.reason = reason;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 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
@@ -23,14 +23,17 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
-public class DeoptimizingStubCall extends DeoptimizingFixedWithNextNode {
+public abstract class DeoptimizingStubCall extends DeoptimizingFixedWithNextNode {
 
-    public DeoptimizingStubCall(Stamp stamp) {
-        super(stamp);
+    public static final NodeClass<DeoptimizingStubCall> TYPE = NodeClass.create(DeoptimizingStubCall.class);
+
+    public DeoptimizingStubCall(NodeClass<? extends DeoptimizingStubCall> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -41,10 +42,11 @@
 @NodeInfo
 public final class DimensionsNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<DimensionsNode> TYPE = NodeClass.create(DimensionsNode.class);
     protected final int rank;
 
     public DimensionsNode(int rank) {
-        super(null);
+        super(TYPE, null);
         this.rank = rank;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -40,6 +41,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class DirectCompareAndSwapNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<DirectCompareAndSwapNode> TYPE = NodeClass.create(DirectCompareAndSwapNode.class);
     @Input ValueNode object;
     @Input ValueNode offset;
     @Input ValueNode expectedValue;
@@ -48,7 +50,7 @@
     protected final LocationIdentity locationIdentity;
 
     public DirectCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, LocationIdentity locationIdentity) {
-        super(expected.stamp());
+        super(TYPE, expected.stamp());
         this.object = object;
         this.offset = offset;
         this.expectedValue = expected;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -34,10 +35,11 @@
  * object.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorExit, MemoryCheckpoint.Single {
+public final class EndLockScopeNode extends AbstractMemoryCheckpoint implements LIRLowerable, MonitorExit, MemoryCheckpoint.Single {
+    public static final NodeClass<EndLockScopeNode> TYPE = NodeClass.create(EndLockScopeNode.class);
 
     public EndLockScopeNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
@@ -36,7 +37,8 @@
  * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
  */
 @NodeInfo
-public class EnterUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+public final class EnterUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<EnterUnpackFramesStackFrameNode> TYPE = NodeClass.create(EnterUnpackFramesStackFrameNode.class);
 
     @Input ValueNode framePc;
     @Input ValueNode senderSp;
@@ -44,7 +46,7 @@
     @Input SaveAllRegistersNode registerSaver;
 
     public EnterUnpackFramesStackFrameNode(ValueNode framePc, ValueNode senderSp, ValueNode senderFp, ValueNode registerSaver) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.framePc = framePc;
         this.senderSp = senderSp;
         this.senderFp = senderFp;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,14 +22,16 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
 public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<G1ArrayRangePostWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class);
 
     public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, startIndex, length);
+        super(TYPE, object, startIndex, length);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,14 +22,16 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
 public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
+    public static final NodeClass<G1ArrayRangePreWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class);
 
     public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, startIndex, length);
+        super(TYPE, object, startIndex, length);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -29,10 +30,15 @@
 @NodeInfo
 public class G1PostWriteBarrier extends WriteBarrier {
 
+    public static final NodeClass<G1PostWriteBarrier> TYPE = NodeClass.create(G1PostWriteBarrier.class);
     protected final boolean alwaysNull;
 
     public G1PostWriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise, boolean alwaysNull) {
-        super(object, value, location, precise);
+        this(TYPE, object, value, location, precise, alwaysNull);
+    }
+
+    protected G1PostWriteBarrier(NodeClass<? extends G1PostWriteBarrier> c, ValueNode object, ValueNode value, LocationNode location, boolean precise, boolean alwaysNull) {
+        super(c, object, value, location, precise);
         this.alwaysNull = alwaysNull;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -29,12 +30,14 @@
 @NodeInfo
 public final class G1PreWriteBarrier extends WriteBarrier implements DeoptimizingNode.DeoptBefore {
 
+    public static final NodeClass<G1PreWriteBarrier> TYPE = NodeClass.create(G1PreWriteBarrier.class);
+
     @OptionalInput(InputType.State) FrameState stateBefore;
     protected final boolean nullCheck;
     protected final boolean doLoad;
 
     public G1PreWriteBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad, boolean nullCheck) {
-        super(object, expectedObject, location, true);
+        super(TYPE, object, expectedObject, location, true);
         this.doLoad = doLoad;
         this.nullCheck = nullCheck;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ReferentFieldReadBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ReferentFieldReadBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -34,11 +35,12 @@
  */
 @NodeInfo
 public final class G1ReferentFieldReadBarrier extends WriteBarrier {
+    public static final NodeClass<G1ReferentFieldReadBarrier> TYPE = NodeClass.create(G1ReferentFieldReadBarrier.class);
 
     protected final boolean doLoad;
 
     public G1ReferentFieldReadBarrier(ValueNode object, ValueNode expectedObject, LocationNode location, boolean doLoad) {
-        super(object, expectedObject, location, true);
+        super(TYPE, object, expectedObject, location, true);
         this.doLoad = doLoad;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,11 +36,12 @@
  */
 @NodeInfo
 public final class GetObjectAddressNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<GetObjectAddressNode> TYPE = NodeClass.create(GetObjectAddressNode.class);
 
     @Input ValueNode object;
 
     public GetObjectAddressNode(ValueNode obj) {
-        super(StampFactory.forKind(Kind.Long));
+        super(TYPE, StampFactory.forKind(Kind.Long));
         this.object = obj;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java	Sat Feb 21 19:55:33 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
@@ -27,13 +27,16 @@
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
-public class HotSpotDirectCallTargetNode extends DirectCallTargetNode {
+public final class HotSpotDirectCallTargetNode extends DirectCallTargetNode {
+    public static final NodeClass<HotSpotDirectCallTargetNode> TYPE = NodeClass.create(HotSpotDirectCallTargetNode.class);
+
     public HotSpotDirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, Type callType, InvokeKind invokeKind) {
-        super(arguments, returnStamp, signature, target, callType, invokeKind);
+        super(TYPE, arguments, returnStamp, signature, target, callType, invokeKind);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,17 +27,19 @@
 import com.oracle.graal.api.code.CallingConvention.Type;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
 public final class HotSpotIndirectCallTargetNode extends IndirectCallTargetNode {
+    public static final NodeClass<HotSpotIndirectCallTargetNode> TYPE = NodeClass.create(HotSpotIndirectCallTargetNode.class);
 
     @Input ValueNode metaspaceMethod;
 
     public HotSpotIndirectCallTargetNode(ValueNode metaspaceMethod, ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target,
                     Type callType, InvokeKind invokeKind) {
-        super(computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
+        super(TYPE, computedAddress, arguments, returnStamp, signature, target, callType, invokeKind);
         this.metaspaceMethod = metaspaceMethod;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -34,14 +35,15 @@
  * exception handler in the caller's frame, removes the current frame and jumps to said handler.
  */
 @NodeInfo
-public class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable {
+public final class JumpToExceptionHandlerInCallerNode extends ControlSinkNode implements LIRLowerable {
 
+    public static final NodeClass<JumpToExceptionHandlerInCallerNode> TYPE = NodeClass.create(JumpToExceptionHandlerInCallerNode.class);
     @Input ValueNode handlerInCallerPc;
     @Input ValueNode exception;
     @Input ValueNode exceptionPc;
 
     public JumpToExceptionHandlerInCallerNode(ValueNode handlerInCallerPc, ValueNode exception, ValueNode exceptionPc) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.handlerInCallerPc = handlerInCallerPc;
         this.exception = exception;
         this.exceptionPc = exceptionPc;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
@@ -34,12 +35,13 @@
  * return address if its location is on the stack.
  */
 @NodeInfo
-public class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+public final class LeaveCurrentStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<LeaveCurrentStackFrameNode> TYPE = NodeClass.create(LeaveCurrentStackFrameNode.class);
     @Input SaveAllRegistersNode registerSaver;
 
     public LeaveCurrentStackFrameNode(ValueNode registerSaver) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.registerSaver = (SaveAllRegistersNode) registerSaver;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodeinfo.*;
@@ -36,13 +37,14 @@
  * is only used in {@link DeoptimizationStub}.
  */
 @NodeInfo
-public class LeaveDeoptimizedStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+public final class LeaveDeoptimizedStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<LeaveDeoptimizedStackFrameNode> TYPE = NodeClass.create(LeaveDeoptimizedStackFrameNode.class);
     @Input ValueNode frameSize;
     @Input ValueNode initialInfo;
 
     public LeaveDeoptimizedStackFrameNode(ValueNode frameSize, ValueNode initialInfo) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.frameSize = frameSize;
         this.initialInfo = initialInfo;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
@@ -34,12 +35,13 @@
  * {@link HotSpotBackend#UNPACK_FRAMES Deoptimization::unpack_frames}.
  */
 @NodeInfo
-public class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
+public final class LeaveUnpackFramesStackFrameNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<LeaveUnpackFramesStackFrameNode> TYPE = NodeClass.create(LeaveUnpackFramesStackFrameNode.class);
     @Input SaveAllRegistersNode registerSaver;
 
     public LeaveUnpackFramesStackFrameNode(ValueNode registerSaver) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.registerSaver = (SaveAllRegistersNode) registerSaver;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadIndexedPointerNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadIndexedPointerNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -31,8 +32,10 @@
 @NodeInfo
 public final class LoadIndexedPointerNode extends LoadIndexedNode {
 
+    public static final NodeClass<LoadIndexedPointerNode> TYPE = NodeClass.create(LoadIndexedPointerNode.class);
+
     public LoadIndexedPointerNode(Stamp stamp, ValueNode array, ValueNode index) {
-        super(stamp, array, index, Kind.Illegal);
+        super(TYPE, stamp, array, index, Kind.Illegal);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
@@ -36,9 +37,10 @@
  */
 @NodeInfo
 public final class MonitorCounterNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<MonitorCounterNode> TYPE = NodeClass.create(MonitorCounterNode.class);
 
     public MonitorCounterNode() {
-        super(null);
+        super(TYPE, null);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.hotspot.word.*;
@@ -40,13 +41,14 @@
 @NodeInfo
 public final class NewArrayStubCall extends DeoptimizingStubCall implements LIRLowerable {
 
+    public static final NodeClass<NewArrayStubCall> TYPE = NodeClass.create(NewArrayStubCall.class);
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
     @Input ValueNode hub;
     @Input ValueNode length;
 
     public NewArrayStubCall(ValueNode hub, ValueNode length) {
-        super(defaultStamp);
+        super(TYPE, defaultStamp);
         this.hub = hub;
         this.length = length;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.hotspot.word.*;
@@ -40,12 +41,13 @@
 @NodeInfo
 public final class NewInstanceStubCall extends DeoptimizingStubCall implements LIRLowerable {
 
+    public static final NodeClass<NewInstanceStubCall> TYPE = NodeClass.create(NewInstanceStubCall.class);
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
     @Input ValueNode hub;
 
     public NewInstanceStubCall(ValueNode hub) {
-        super(defaultStamp);
+        super(TYPE, defaultStamp);
         this.hub = hub;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -40,6 +41,7 @@
 @NodeInfo
 public final class NewMultiArrayStubCall extends ForeignCallNode {
 
+    public static final NodeClass<NewMultiArrayStubCall> TYPE = NodeClass.create(NewMultiArrayStubCall.class);
     private static final Stamp defaultStamp = StampFactory.objectNonNull();
 
     @Input ValueNode hub;
@@ -47,7 +49,7 @@
     protected final int rank;
 
     public NewMultiArrayStubCall(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode hub, int rank, ValueNode dims) {
-        super(foreignCalls, NEW_MULTI_ARRAY, defaultStamp);
+        super(TYPE, foreignCalls, NEW_MULTI_ARRAY, defaultStamp);
         this.hub = hub;
         this.rank = rank;
         this.dims = dims;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -33,12 +34,13 @@
  * Modifies the return address of the current frame.
  */
 @NodeInfo
-public class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable {
+public final class PatchReturnAddressNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<PatchReturnAddressNode> TYPE = NodeClass.create(PatchReturnAddressNode.class);
     @Input ValueNode address;
 
     public PatchReturnAddressNode(ValueNode address) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.address = address;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -24,6 +24,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -31,13 +32,14 @@
 import com.oracle.graal.word.*;
 
 @NodeInfo
-public class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
+public final class PrefetchAllocateNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<PrefetchAllocateNode> TYPE = NodeClass.create(PrefetchAllocateNode.class);
     @Input ValueNode distance;
     @Input ValueNode address;
 
     public PrefetchAllocateNode(ValueNode address, ValueNode distance) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.address = address;
         this.distance = distance;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -34,15 +35,16 @@
  * A call to the runtime code implementing the uncommon trap logic.
  */
 @NodeInfo
-public class PushInterpreterFrameNode extends FixedWithNextNode implements LIRLowerable {
+public final class PushInterpreterFrameNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<PushInterpreterFrameNode> TYPE = NodeClass.create(PushInterpreterFrameNode.class);
     @Input ValueNode framePc;
     @Input ValueNode frameSize;
     @Input ValueNode senderSp;
     @Input ValueNode initialInfo;
 
     public PushInterpreterFrameNode(ValueNode frameSize, ValueNode framePc, ValueNode senderSp, ValueNode initialInfo) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.frameSize = frameSize;
         this.framePc = framePc;
         this.senderSp = senderSp;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
@@ -35,12 +36,13 @@
  * Saves all allocatable registers.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class SaveAllRegistersNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+public final class SaveAllRegistersNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<SaveAllRegistersNode> TYPE = NodeClass.create(SaveAllRegistersNode.class);
     protected SaveRegistersOp saveRegistersOp;
 
     public SaveAllRegistersNode() {
-        super(StampFactory.forKind(Kind.Long));
+        super(TYPE, StampFactory.forKind(Kind.Long));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Sat Feb 21 19:55:33 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
@@ -22,14 +22,17 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
-public class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
+public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
+
+    public static final NodeClass<SerialArrayRangeWriteBarrier> TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class);
 
     public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(object, startIndex, length);
+        super(TYPE, object, startIndex, length);
     }
 
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Sat Feb 21 19:55:33 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -29,10 +30,15 @@
 @NodeInfo
 public class SerialWriteBarrier extends WriteBarrier {
 
+    public static final NodeClass<SerialWriteBarrier> TYPE = NodeClass.create(SerialWriteBarrier.class);
     protected final boolean alwaysNull;
 
     public SerialWriteBarrier(ValueNode object, LocationNode location, boolean precise, boolean alwaysNull) {
-        super(object, null, location, precise);
+        this(TYPE, object, location, precise, alwaysNull);
+    }
+
+    protected SerialWriteBarrier(NodeClass<? extends SerialWriteBarrier> c, ValueNode object, LocationNode location, boolean precise, boolean alwaysNull) {
+        super(c, object, null, location, precise);
         this.alwaysNull = alwaysNull;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 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
@@ -23,16 +23,18 @@
 package com.oracle.graal.hotspot.nodes;
 
 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.extended.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Value, InputType.Anchor, InputType.Guard})
-public class SnippetAnchorNode extends FixedWithNextNode implements Simplifiable, GuardingNode {
+public final class SnippetAnchorNode extends FixedWithNextNode implements Simplifiable, GuardingNode {
+    public static final NodeClass<SnippetAnchorNode> TYPE = NodeClass.create(SnippetAnchorNode.class);
 
     public SnippetAnchorNode() {
-        super(StampFactory.object());
+        super(TYPE, StampFactory.object());
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 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
@@ -31,12 +31,13 @@
 import com.oracle.graal.nodes.extended.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Association, InputType.Value})
-public class SnippetLocationProxyNode extends FloatingNode implements Canonicalizable {
+public final class SnippetLocationProxyNode extends FloatingNode implements Canonicalizable {
 
+    public static final NodeClass<SnippetLocationProxyNode> TYPE = NodeClass.create(SnippetLocationProxyNode.class);
     @Input(InputType.Unchecked) ValueNode location;
 
     public SnippetLocationProxyNode(ValueNode location) {
-        super(StampFactory.object());
+        super(TYPE, StampFactory.object());
         this.location = location;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,15 +38,16 @@
  * Node for a {@linkplain ForeignCallDescriptor foreign} call from within a stub.
  */
 @NodeInfo(nameTemplate = "StubForeignCall#{p#descriptor/s}", allowedUsageTypes = {InputType.Memory})
-public class StubForeignCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+public final class StubForeignCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
 
+    public static final NodeClass<StubForeignCallNode> TYPE = NodeClass.create(StubForeignCallNode.class);
     @Input NodeInputList<ValueNode> arguments;
     protected final ForeignCallsProvider foreignCalls;
 
     protected final ForeignCallDescriptor descriptor;
 
     public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
-        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        super(TYPE, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java	Sat Feb 21 19:55:33 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.hotspot.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -30,11 +31,13 @@
  * Start node for a {@link Stub}'s graph.
  */
 @NodeInfo
-public class StubStartNode extends StartNode {
+public final class StubStartNode extends StartNode {
 
+    public static final NodeClass<StubStartNode> TYPE = NodeClass.create(StubStartNode.class);
     protected final Stub stub;
 
     public StubStartNode(Stub stub) {
+        super(TYPE);
         this.stub = stub;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
 import com.oracle.graal.nodeinfo.*;
@@ -39,14 +40,15 @@
  * A call to the runtime code implementing the uncommon trap logic.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
+public final class UncommonTrapCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Multi {
 
+    public static final NodeClass<UncommonTrapCallNode> TYPE = NodeClass.create(UncommonTrapCallNode.class);
     @Input ValueNode trapRequest;
     @Input SaveAllRegistersNode registerSaver;
     protected final ForeignCallsProvider foreignCalls;
 
     public UncommonTrapCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode trapRequest) {
-        super(StampFactory.forKind(Kind.fromJavaClass(UNCOMMON_TRAP.getResultType())));
+        super(TYPE, StampFactory.forKind(Kind.fromJavaClass(UNCOMMON_TRAP.getResultType())));
         this.trapRequest = trapRequest;
         this.registerSaver = (SaveAllRegistersNode) registerSaver;
         this.foreignCalls = foreignCalls;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -38,13 +39,14 @@
  * {@linkplain Log#printf(String, long) formatted} error message specified.
  */
 @NodeInfo
-public class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable {
+public final class VMErrorNode extends DeoptimizingStubCall implements LIRLowerable {
 
+    public static final NodeClass<VMErrorNode> TYPE = NodeClass.create(VMErrorNode.class);
     protected final String format;
     @Input ValueNode value;
 
     public VMErrorNode(String format, ValueNode value) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.format = format;
         this.value = value;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -31,13 +32,14 @@
 @NodeInfo
 public abstract class WriteBarrier extends FixedWithNextNode implements Lowerable {
 
+    public static final NodeClass<WriteBarrier> TYPE = NodeClass.create(WriteBarrier.class);
     @Input protected ValueNode object;
     @OptionalInput protected ValueNode value;
     @OptionalInput(InputType.Association) protected LocationNode location;
     protected final boolean precise;
 
-    public WriteBarrier(ValueNode object, ValueNode value, LocationNode location, boolean precise) {
-        super(StampFactory.forVoid());
+    protected WriteBarrier(NodeClass<? extends WriteBarrier> c, ValueNode object, ValueNode value, LocationNode location, boolean precise) {
+        super(c, StampFactory.forVoid());
         this.object = object;
         this.value = value;
         this.location = location;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -49,7 +49,7 @@
         Debug.dump(graph, "OnStackReplacement initial");
         EntryMarkerNode osr;
         do {
-            NodeIterable<EntryMarkerNode> osrNodes = graph.getNodes(EntryMarkerNode.class);
+            NodeIterable<EntryMarkerNode> osrNodes = graph.getNodes(EntryMarkerNode.TYPE);
             osr = osrNodes.first();
             if (osr == null) {
                 throw new BailoutException("No OnStackReplacementNode generated");
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Sat Feb 21 19:55:33 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.*;
@@ -35,18 +34,20 @@
 @NodeInfo
 public final class CallSiteTargetNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
 
+    public static final NodeClass<CallSiteTargetNode> TYPE = NodeClass.create(CallSiteTargetNode.class);
+
     public CallSiteTargetNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private ValueNode getCallSite() {
         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 +57,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 +67,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/CardTableAddressNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CardTableAddressNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
@@ -31,9 +32,10 @@
 
 @NodeInfo
 public final class CardTableAddressNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<CardTableAddressNode> TYPE = NodeClass.create(CardTableAddressNode.class);
 
     public CardTableAddressNode() {
-        super(StampFactory.forKind(Kind.Long));
+        super(TYPE, StampFactory.forKind(Kind.Long));
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CardTableShiftNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CardTableShiftNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
@@ -31,9 +32,10 @@
 
 @NodeInfo
 public final class CardTableShiftNode extends FloatingNode implements LIRLowerable {
+    public static final NodeClass<CardTableShiftNode> TYPE = NodeClass.create(CardTableShiftNode.class);
 
     public CardTableShiftNode() {
-        super(StampFactory.intValue());
+        super(TYPE, StampFactory.intValue());
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -43,6 +43,7 @@
  */
 @NodeInfo
 public final class ClassGetHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode {
+    public static final NodeClass<ClassGetHubNode> TYPE = NodeClass.create(ClassGetHubNode.class);
     @Input protected ValueNode clazz;
 
     public ClassGetHubNode(ValueNode clazz) {
@@ -50,7 +51,7 @@
     }
 
     public ClassGetHubNode(ValueNode clazz, ValueNode guard) {
-        super(KlassPointerStamp.klass(), (GuardingNode) guard);
+        super(TYPE, KlassPointerStamp.klass(), (GuardingNode) guard);
         this.clazz = clazz;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2012, 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.hotspot.replacements;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.PiNode.*;
-
-import java.lang.reflect.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.nodes.*;
-import com.oracle.graal.hotspot.word.*;
-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.word.*;
-
-/**
- * Substitutions for {@link java.lang.Class} methods.
- */
-@ClassSubstitution(java.lang.Class.class)
-public class ClassSubstitutions {
-
-    @MacroSubstitution(macro = ClassGetModifiersNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static int getModifiers(final Class<?> thisObj) {
-        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
-        if (klass.isNull()) {
-            // Class for primitive type
-            return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
-        } else {
-            return klass.readInt(klassModifierFlagsOffset(), KLASS_MODIFIER_FLAGS_LOCATION);
-        }
-    }
-
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsInterfaceNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static boolean isInterface(final Class<?> thisObj) {
-        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
-        if (klass.isNull()) {
-            return false;
-        } else {
-            int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION);
-            return (accessFlags & Modifier.INTERFACE) != 0;
-        }
-    }
-
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsArrayNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static boolean isArray(final Class<?> thisObj) {
-        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
-        if (klass.isNull()) {
-            return false;
-        } else {
-            return klassIsArray(klass);
-        }
-    }
-
-    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
-    @MacroSubstitution(macro = ClassIsPrimitiveNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false, forced = true)
-    public static boolean isPrimitive(final Class<?> thisObj) {
-        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
-        return klass.isNull();
-    }
-
-    @MacroSubstitution(macro = ClassGetClassLoader0Node.class, isStatic = false)
-    public static native ClassLoader getClassLoader0(Class<?> thisObj);
-
-    @MacroSubstitution(macro = ClassGetSuperclassNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
-    public static Class<?> getSuperclass(final Class<?> thisObj) {
-        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
-        if (!klass.isNull()) {
-            int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION);
-            if ((accessFlags & Modifier.INTERFACE) == 0) {
-                if (klassIsArray(klass)) {
-                    return Object.class;
-                } else {
-                    Word superKlass = klass.readWord(klassSuperKlassOffset(), KLASS_SUPER_KLASS_LOCATION);
-                    if (superKlass.equal(0)) {
-                        return null;
-                    } else {
-                        return readJavaMirror(superKlass);
-                    }
-                }
-            }
-        }
-        return null;
-    }
-
-    public static Class<?> readJavaMirror(Word klass) {
-        return piCastExactNonNull(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION), Class.class);
-    }
-
-    @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
-    public static Class<?> getComponentType(final Class<?> thisObj) {
-        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
-        if (!klass.isNull()) {
-            if (klassIsArray(klass)) {
-                return piCastExactNonNull(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR), Class.class);
-            }
-        }
-        return null;
-    }
-
-    @MacroSubstitution(macro = ClassIsInstanceNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
-    public static boolean isInstance(Class<?> thisObj, Object obj) {
-        return ConditionalNode.materializeIsInstance(thisObj, obj);
-    }
-
-    @MacroSubstitution(macro = ClassIsAssignableFromNode.class, isStatic = false)
-    @MethodSubstitution(isStatic = false)
-    public static boolean isAssignableFrom(Class<?> thisClass, Class<?> otherClass) {
-        if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_LIKELY_PROBABILITY, otherClass == null)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
-            return false;
-        }
-        GuardingNode anchorNode = SnippetAnchorNode.anchor();
-        KlassPointer thisHub = ClassGetHubNode.readClass(thisClass, anchorNode);
-        KlassPointer otherHub = ClassGetHubNode.readClass(otherClass, anchorNode);
-        if (thisHub.isNull() || otherHub.isNull()) {
-            // primitive types, only true if equal.
-            return thisClass == otherClass;
-        }
-        if (!TypeCheckSnippetUtils.checkUnknownSubType(thisHub, otherHub)) {
-            return false;
-        }
-        return true;
-    }
-
-    @MacroSubstitution(macro = ClassCastNode.class, isStatic = false)
-    public static native Object cast(final Class<?> thisObj, Object obj);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompilerToVMImplSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompilerToVMImplSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,6 +34,6 @@
 
     @MethodSubstitution(isStatic = false)
     public static Class<?> getJavaMirror(@SuppressWarnings("unused") CompilerToVMImpl impl, long metaspaceklass) {
-        return ClassSubstitutions.readJavaMirror(Word.unsigned(metaspaceklass));
+        return HotSpotClassSubstitutions.readJavaMirror(Word.unsigned(metaspaceklass));
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CompositeValueClassSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2011, 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.hotspot.replacements;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Substitutions for improving the performance of {@link CompositeValueClass#getClass()}.
- */
-@ClassSubstitution(CompositeValueClass.class)
-public class CompositeValueClassSubstitutions {
-
-    /**
-     * A macro node for calls to {@link CompositeValueClass#get(Class)}. It can use the compiler's
-     * knowledge about node classes to replace itself with a constant value for a constant
-     * {@link Class} parameter.
-     */
-    @NodeInfo
-    public static final class CompositeValueClassGetNode extends PureFunctionMacroNode {
-
-        public CompositeValueClassGetNode(Invoke invoke) {
-            super(invoke);
-        }
-
-        @Override
-        protected JavaConstant evaluate(JavaConstant param, MetaAccessProvider metaAccess) {
-            if (param.isNull() || ImmutableCode.getValue()) {
-                return null;
-            }
-            HotSpotObjectConstant c = (HotSpotObjectConstant) param;
-            return c.getCompositeValueClass();
-        }
-    }
-
-    @MacroSubstitution(isStatic = true, forced = true, macro = CompositeValueClassGetNode.class)
-    private static native CompositeValueClass get(Class<?> c);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotClassSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2012, 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.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.nodes.PiNode.*;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.word.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.word.*;
+
+/**
+ * Substitutions for {@link java.lang.Class} methods.
+ */
+@ClassSubstitution(java.lang.Class.class)
+public class HotSpotClassSubstitutions {
+
+    @MacroSubstitution(macro = ClassGetModifiersNode.class, isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
+    public static int getModifiers(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (klass.isNull()) {
+            // Class for primitive type
+            return Modifier.ABSTRACT | Modifier.FINAL | Modifier.PUBLIC;
+        } else {
+            return klass.readInt(klassModifierFlagsOffset(), KLASS_MODIFIER_FLAGS_LOCATION);
+        }
+    }
+
+    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
+    @MacroSubstitution(macro = ClassIsInterfaceNode.class, isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
+    public static boolean isInterface(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (klass.isNull()) {
+            return false;
+        } else {
+            int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION);
+            return (accessFlags & Modifier.INTERFACE) != 0;
+        }
+    }
+
+    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
+    @MacroSubstitution(macro = ClassIsArrayNode.class, isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
+    public static boolean isArray(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (klass.isNull()) {
+            return false;
+        } else {
+            return klassIsArray(klass);
+        }
+    }
+
+    // This MacroSubstitution should be removed once non-null klass pointers can be optimized
+    @MacroSubstitution(macro = ClassIsPrimitiveNode.class, isStatic = false)
+    @MethodSubstitution(isStatic = false, forced = true)
+    public static boolean isPrimitive(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        return klass.isNull();
+    }
+
+    @MacroSubstitution(macro = ClassGetClassLoader0Node.class, isStatic = false)
+    public static native ClassLoader getClassLoader0(Class<?> thisObj);
+
+    @MacroSubstitution(macro = ClassGetSuperclassNode.class, isStatic = false)
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getSuperclass(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (!klass.isNull()) {
+            int accessFlags = klass.readInt(klassAccessFlagsOffset(), KLASS_ACCESS_FLAGS_LOCATION);
+            if ((accessFlags & Modifier.INTERFACE) == 0) {
+                if (klassIsArray(klass)) {
+                    return Object.class;
+                } else {
+                    Word superKlass = klass.readWord(klassSuperKlassOffset(), KLASS_SUPER_KLASS_LOCATION);
+                    if (superKlass.equal(0)) {
+                        return null;
+                    } else {
+                        return readJavaMirror(superKlass);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    public static Class<?> readJavaMirror(Word klass) {
+        return piCastExactNonNull(klass.readObject(classMirrorOffset(), CLASS_MIRROR_LOCATION), Class.class);
+    }
+
+    @MacroSubstitution(macro = ClassGetComponentTypeNode.class, isStatic = false)
+    @MethodSubstitution(isStatic = false)
+    public static Class<?> getComponentType(final Class<?> thisObj) {
+        KlassPointer klass = ClassGetHubNode.readClass(thisObj);
+        if (!klass.isNull()) {
+            if (klassIsArray(klass)) {
+                return piCastExactNonNull(klass.readObject(arrayKlassComponentMirrorOffset(), ARRAY_KLASS_COMPONENT_MIRROR), Class.class);
+            }
+        }
+        return null;
+    }
+
+    @MacroSubstitution(macro = ClassCastNode.class, isStatic = false)
+    public static native Object cast(final Class<?> thisObj, Object obj);
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotGraphBuilderPluginsProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +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.replacements;
-
-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.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.*;
-
-/**
- * Provider of HotSpot specific {@link GraphBuilderPlugin}s.
- */
-@ServiceProvider(GraphBuilderPluginsProvider.class)
-public class HotSpotGraphBuilderPluginsProvider implements GraphBuilderPluginsProvider {
-    public void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        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(), metaAccess));
-                } 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;
-            }
-        });
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeClassSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2011, 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.hotspot.replacements;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Substitutions for improving the performance of {@link NodeClass#get}.
- */
-@ClassSubstitution(NodeClass.class)
-public class HotSpotNodeClassSubstitutions {
-
-    /**
-     * A macro node for calls to {@link NodeClass#get(Class)}. It can use the compiler's knowledge
-     * about node classes to replace itself with a constant value for a constant {@link Class}
-     * parameter.
-     */
-    @NodeInfo
-    public static class NodeClassGetNode extends PureFunctionMacroNode {
-
-        public NodeClassGetNode(Invoke invoke) {
-            super(invoke);
-        }
-
-        @Override
-        protected JavaConstant evaluate(JavaConstant param, MetaAccessProvider metaAccess) {
-            if (param.isNull() || ImmutableCode.getValue()) {
-                return null;
-            }
-            HotSpotObjectConstant c = (HotSpotObjectConstant) param;
-            return c.getNodeClass();
-        }
-    }
-
-    /**
-     * NOTE: A {@link MethodSubstitution} similar to
-     * {@link HotSpotNodeSubstitutions#getNodeClass(Node)} is not possible here because there is no
-     * guarantee that {@code c} is initialized (accessing a Class literal in Java is not a class
-     * initialization barrier).
-     */
-    @MacroSubstitution(isStatic = true, forced = true, macro = NodeClassGetNode.class)
-    public static native NodeClass get(Class<?> c);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2011, 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.hotspot.replacements;
-
-import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.PiNode.*;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.word.*;
-
-@ClassSubstitution(Node.class)
-public class HotSpotNodeSubstitutions {
-
-    /**
-     * Gets the value of the {@code InstanceKlass::_graal_node_class} field from the InstanceKlass
-     * pointed to by {@code node}'s header.
-     */
-    @MethodSubstitution(isStatic = false)
-    public static NodeClass getNodeClass(final Node node) {
-        // HotSpot creates the NodeClass for each Node subclass while initializing it
-        // so we are guaranteed to read a non-null value here. As long as NodeClass
-        // is final, the stamp of the PiNode below will automatically be exact.
-        KlassPointer klass = loadHub(node);
-        return piCastNonNull(klass.readObject(Word.signed(instanceKlassNodeClassOffset()), KLASS_NODE_CLASS), NodeClass.class);
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Sat Feb 21 19:55:33 2015 +0100
@@ -661,13 +661,6 @@
         return config().arrayKlassOffset;
     }
 
-    public static final LocationIdentity KLASS_NODE_CLASS = NamedLocationIdentity.immutable("KlassNodeClass");
-
-    @Fold
-    public static int instanceKlassNodeClassOffset() {
-        return config().instanceKlassNodeClassOffset;
-    }
-
     public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror");
 
     @Fold
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,9 +32,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.bridge.*;
-import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.replacements.*;
 
@@ -60,12 +58,9 @@
         replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
         replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class);
-        replacements.registerSubstitutions(Class.class, ClassSubstitutions.class);
+        replacements.registerSubstitutions(Class.class, HotSpotClassSubstitutions.class);
         replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
-        replacements.registerSubstitutions(NodeClass.class, HotSpotNodeClassSubstitutions.class);
-        replacements.registerSubstitutions(Node.class, HotSpotNodeSubstitutions.class);
-        replacements.registerSubstitutions(CompositeValueClass.class, CompositeValueClassSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
         replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
         replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HubGetClassNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HubGetClassNode.java	Sat Feb 21 19:55:33 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
@@ -38,11 +38,12 @@
  * also used by {@link ClassGetHubNode} to eliminate chains of {@code klass._java_mirror._klass}.
  */
 @NodeInfo
-public class HubGetClassNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode {
+public final class HubGetClassNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, ConvertNode {
+    public static final NodeClass<HubGetClassNode> TYPE = NodeClass.create(HubGetClassNode.class);
     @Input protected ValueNode hub;
 
-    protected HubGetClassNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode hub) {
-        super(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Class.class)), null);
+    public HubGetClassNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode hub) {
+        super(TYPE, StampFactory.declaredNonNull(metaAccess.lookupJavaType(Class.class)), null);
         this.hub = hub;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,6 +32,7 @@
 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.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -60,17 +61,26 @@
  */
 public class InstanceOfSnippets implements Snippets {
 
+    private static final double COMPILED_VS_INTERPRETER_SPEEDUP = 50;
+    private static final double INSTANCEOF_DEOPT_SPEEDUP = 1.01; // generous 1% speedup
+
+    private static final int DEOPT_THRESHOLD_FACTOR = (int) (COMPILED_VS_INTERPRETER_SPEEDUP / (INSTANCEOF_DEOPT_SPEEDUP - 1.0));
+
     /**
      * Gets the minimum required probability of a profiled instanceof hitting one the profiled types
      * for use of the {@linkplain #instanceofWithProfile deoptimizing} snippet. The value is
-     * computed to be an order of magnitude greater than the configured compilation threshold. For
-     * example, if a method is compiled after being interpreted 10000 times, the deoptimizing
-     * snippet will only be used for an instanceof if its profile indicates that less than 1 in
-     * 100000 executions are for an object whose type is not one of the top N profiled types (where
-     * {@code N == } {@link Options#TypeCheckMaxHints}).
+     * computed to be an order of greater than the configured compilation threshold by a
+     * {@linkplain #DEOPT_THRESHOLD_FACTOR factor}.
+     *
+     * <p>
+     * This factor is such that the additional executions we get from using the deoptimizing snippet
+     * (({@linkplain #INSTANCEOF_DEOPT_SPEEDUP speedup} - 1) / probability threshold) is greater
+     * than the time lost during re-interpretation ({@linkplain #COMPILED_VS_INTERPRETER_SPEEDUP
+     * compiled code speedup} &times compilation threshold).
+     * </p>
      */
     public static double hintHitProbabilityThresholdForDeoptimizingSnippet(long compilationThreshold) {
-        return 1.0D - (1.0D / (compilationThreshold * 10));
+        return 1.0D - (1.0D / (compilationThreshold * DEOPT_THRESHOLD_FACTOR));
     }
 
     /**
@@ -194,6 +204,25 @@
         return trueValue;
     }
 
+    @Snippet
+    public static Object isAssignableFrom(Class<?> thisClass, Class<?> otherClass, Object trueValue, Object falseValue) {
+        if (BranchProbabilityNode.probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, otherClass == null)) {
+            DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
+            return false;
+        }
+        GuardingNode anchorNode = SnippetAnchorNode.anchor();
+        KlassPointer thisHub = ClassGetHubNode.readClass(thisClass, anchorNode);
+        KlassPointer otherHub = ClassGetHubNode.readClass(otherClass, anchorNode);
+        if (thisHub.isNull() || otherHub.isNull()) {
+            // primitive types, only true if equal.
+            return thisClass == otherClass ? trueValue : falseValue;
+        }
+        if (!TypeCheckSnippetUtils.checkUnknownSubType(thisHub, otherHub)) {
+            return falseValue;
+        }
+        return trueValue;
+    }
+
     static class Options {
 
         // @formatter:off
@@ -214,6 +243,7 @@
         private final SnippetInfo instanceofPrimary = snippet(InstanceOfSnippets.class, "instanceofPrimary");
         private final SnippetInfo instanceofSecondary = snippet(InstanceOfSnippets.class, "instanceofSecondary");
         private final SnippetInfo instanceofDynamic = snippet(InstanceOfSnippets.class, "instanceofDynamic");
+        private final SnippetInfo isAssignableFrom = snippet(InstanceOfSnippets.class, "isAssignableFrom");
         private final long compilationThreshold;
 
         public Templates(HotSpotProviders providers, TargetDescription target, long compilationThreshold) {
@@ -226,7 +256,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());
 
@@ -263,8 +294,7 @@
                 }
                 return args;
 
-            } else {
-                assert replacer.instanceOf instanceof InstanceOfDynamicNode;
+            } else if (replacer.instanceOf instanceof InstanceOfDynamicNode) {
                 InstanceOfDynamicNode instanceOf = (InstanceOfDynamicNode) replacer.instanceOf;
                 ValueNode object = instanceOf.object();
 
@@ -274,6 +304,16 @@
                 args.add("trueValue", replacer.trueValue);
                 args.add("falseValue", replacer.falseValue);
                 return args;
+            } else if (replacer.instanceOf instanceof ClassIsAssignableFromNode) {
+                ClassIsAssignableFromNode isAssignable = (ClassIsAssignableFromNode) replacer.instanceOf;
+                Arguments args = new Arguments(isAssignableFrom, isAssignable.graph().getGuardsStage(), tool.getLoweringStage());
+                args.add("thisClass", isAssignable.getThisClass());
+                args.add("otherClass", isAssignable.getOtherClass());
+                args.add("trueValue", replacer.trueValue);
+                args.add("falseValue", replacer.falseValue);
+                return args;
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
             }
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/KlassLayoutHelperNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/KlassLayoutHelperNode.java	Sat Feb 21 19:55:33 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
@@ -38,8 +38,9 @@
  * information in {@code klass}.
  */
 @NodeInfo
-public class KlassLayoutHelperNode extends FloatingGuardedNode implements Canonicalizable, Lowerable {
+public final class KlassLayoutHelperNode extends FloatingGuardedNode implements Canonicalizable, Lowerable {
 
+    public static final NodeClass<KlassLayoutHelperNode> TYPE = NodeClass.create(KlassLayoutHelperNode.class);
     @Input protected ValueNode klass;
     protected final HotSpotVMConfig config;
 
@@ -48,7 +49,7 @@
     }
 
     public KlassLayoutHelperNode(@InjectedNodeParameter HotSpotVMConfig config, ValueNode klass, ValueNode guard) {
-        super(StampFactory.forKind(Kind.Int), (GuardingNode) guard);
+        super(TYPE, StampFactory.forKind(Kind.Int), (GuardingNode) guard);
         this.klass = klass;
         this.config = config;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@
  */
 @NodeInfo
 public final class MethodHandleNode extends MacroStateSplitNode implements Simplifiable {
+    public static final NodeClass<MethodHandleNode> TYPE = NodeClass.create(MethodHandleNode.class);
 
     // Replacement method data
     protected ResolvedJavaMethod replacementTargetMethod;
@@ -51,7 +52,7 @@
     @Input NodeInputList<ValueNode> replacementArguments;
 
     public MethodHandleNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
         MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
         // See if we need to save some replacement method data.
         if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Sat Feb 21 19:55:33 2015 +0100
@@ -504,7 +504,7 @@
                     StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod());
                     InliningUtil.inline(invoke, inlineeGraph, false, null);
 
-                    List<ReturnNode> rets = graph.getNodes(ReturnNode.class).snapshot();
+                    List<ReturnNode> rets = graph.getNodes(ReturnNode.TYPE).snapshot();
                     for (ReturnNode ret : rets) {
                         returnType = checkCounter.getMethod().getSignature().getReturnType(checkCounter.getMethod().getDeclaringClass());
                         String msg = "unbalanced monitors in " + graph.method().format("%H.%n(%p)") + ", count = %d";
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Sat Feb 21 19:55:33 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
@@ -26,21 +26,26 @@
 
 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.graph.*;
 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.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
-public class ObjectCloneNode extends BasicObjectCloneNode implements VirtualizableAllocation, ArrayLengthProvider {
+public final class ObjectCloneNode extends BasicObjectCloneNode implements VirtualizableAllocation, ArrayLengthProvider {
+
+    public static final NodeClass<ObjectCloneNode> TYPE = NodeClass.create(ObjectCloneNode.class);
 
     public ObjectCloneNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     @Override
@@ -68,9 +73,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/ReflectionGetCallerClassNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,10 +35,12 @@
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
-public class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
+public final class ReflectionGetCallerClassNode extends MacroStateSplitNode implements Canonicalizable, Lowerable {
+
+    public static final NodeClass<ReflectionGetCallerClassNode> TYPE = NodeClass.create(ReflectionGetCallerClassNode.class);
 
     public ReflectionGetCallerClassNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,16 +25,19 @@
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
-public class SystemIdentityHashCodeNode extends PureFunctionMacroNode {
+public final class SystemIdentityHashCodeNode extends PureFunctionMacroNode {
+
+    public static final NodeClass<SystemIdentityHashCodeNode> TYPE = NodeClass.create(SystemIdentityHashCodeNode.class);
 
     public SystemIdentityHashCodeNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -41,6 +42,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class ArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<ArrayCopyCallNode> TYPE = NodeClass.create(ArrayCopyCallNode.class);
     @Input ValueNode src;
     @Input ValueNode srcPos;
     @Input ValueNode dest;
@@ -70,7 +72,7 @@
 
     protected ArrayCopyCallNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, Kind elementKind, boolean aligned, boolean disjoint, boolean uninitialized,
                     HotSpotGraalRuntimeProvider runtime) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         assert elementKind != null;
         this.src = src;
         this.srcPos = srcPos;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 import com.oracle.graal.compiler.common.*;
 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.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -40,8 +41,10 @@
 @NodeInfo
 public final class ArrayCopyNode extends BasicArrayCopyNode implements Virtualizable, Lowerable {
 
+    public static final NodeClass<ArrayCopyNode> TYPE = NodeClass.create(ArrayCopyNode.class);
+
     public ArrayCopyNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     private StructuredGraph selectSnippet(LoweringTool tool, final Replacements replacements) {
@@ -73,7 +76,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/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
@@ -40,6 +41,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value})
 public final class CheckcastArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<CheckcastArrayCopyCallNode> TYPE = NodeClass.create(CheckcastArrayCopyCallNode.class);
     @Input ValueNode src;
     @Input ValueNode srcPos;
     @Input ValueNode dest;
@@ -54,7 +56,7 @@
 
     protected CheckcastArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length,
                     ValueNode superCheckOffset, ValueNode destElemKlass, boolean uninit) {
-        super(StampFactory.forKind(Kind.Int));
+        super(TYPE, StampFactory.forKind(Kind.Int));
         this.src = src;
         this.srcPos = srcPos;
         this.dest = dest;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Sat Feb 21 19:55:33 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
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -33,8 +34,9 @@
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single {
+public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<UnsafeArrayCopyNode> TYPE = NodeClass.create(UnsafeArrayCopyNode.class);
     @Input ValueNode src;
     @Input ValueNode srcPos;
     @Input ValueNode dest;
@@ -45,7 +47,7 @@
     protected Kind elementKind;
 
     public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, Kind elementKind) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         assert layoutHelper == null || elementKind == null;
         this.src = src;
         this.srcPos = srcPos;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,8 +23,10 @@
 package com.oracle.graal.hotspot.stubs;
 
 import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.Options.*;
 import static com.oracle.graal.hotspot.nodes.DeoptimizationFetchUnrollInfoCallNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.hotspot.stubs.UncommonTrapStub.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -84,6 +86,7 @@
     public DeoptimizationStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(DeoptimizationStub.class, "deoptimizationHandler", providers, target, linkage);
         this.target = target;
+        assert PreferGraalStubs.getValue();
     }
 
     @Override
@@ -135,7 +138,7 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
-         * 
+         *
          * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
@@ -143,7 +146,7 @@
         Word stackPointer = readRegister(stackPointerRegister);
 
         for (int i = 1; i < bangPages; i++) {
-            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0, UncommonTrapStub.STACK_BANG_LOCATION);
+            stackPointer.writeInt((-i * pageSize()) + stackBias(), 0, STACK_BANG_LOCATION);
         }
 
         // Load number of interpreter frames.
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Sat Feb 21 19:55:33 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.disableInlinedMethodRecording();
 
         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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/Stub.java	Sat Feb 21 19:55:33 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.*;
@@ -40,6 +39,7 @@
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.schedule.*;
@@ -157,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.isInlinedMethodRecordingEnabled() : graph;
+
                 if (!(graph.start() instanceof StubStartNode)) {
                     StubStartNode newStart = graph.add(new StubStartNode(Stub.this));
                     newStart.setStateAfter(graph.start().stateAfter());
@@ -170,12 +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);
-                    emitBackEnd(graph, Stub.this, incomingCc, getInstalledCodeOwner(), backend, target, compResult, CompilationResultBuilderFactory.Default, assumptions, schedule, getRegisterConfig());
+                    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.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,8 +22,9 @@
  */
 package com.oracle.graal.hotspot.stubs;
 
+import static com.oracle.graal.hotspot.HotSpotBackend.*;
+import static com.oracle.graal.hotspot.HotSpotBackend.Options.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.hotspot.stubs.StubUtil.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
@@ -85,6 +86,7 @@
     public UncommonTrapStub(HotSpotProviders providers, TargetDescription target, HotSpotForeignCallLinkage linkage) {
         super(UncommonTrapStub.class, "uncommonTrapHandler", providers, target, linkage);
         this.target = target;
+        assert PreferGraalStubs.getValue();
     }
 
     @Override
@@ -147,7 +149,7 @@
          * Stack bang to make sure there's enough room for the interpreter frames. Bang stack for
          * total size of the interpreter frames plus shadow page size. Bang one page at a time
          * because large sizes can bang beyond yellow and red zones.
-         * 
+         *
          * @deprecated This code should go away as soon as JDK-8032410 hits the Graal repository.
          */
         final int totalFrameSizes = unrollBlock.readInt(deoptimizationUnrollBlockTotalFrameSizesOffset());
@@ -284,8 +286,6 @@
         return config().deoptimizationUnpackUncommonTrap;
     }
 
-    public static final ForeignCallDescriptor UNPACK_FRAMES = newDescriptor(UncommonTrapStub.class, "unpackFrames", int.class, Word.class, int.class);
-
     @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true)
     public static native int unpackFrames(@ConstantNodeParameter ForeignCallDescriptor unpackFrames, Word thread, int mode);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/PointerCastNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/PointerCastNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -34,12 +35,13 @@
  * {@link HotSpotWordTypeRewriterPhase}.
  */
 @NodeInfo
-public class PointerCastNode extends FloatingNode implements LIRLowerable {
+public final class PointerCastNode extends FloatingNode implements LIRLowerable {
 
+    public static final NodeClass<PointerCastNode> TYPE = NodeClass.create(PointerCastNode.class);
     @Input ValueNode input;
 
     public PointerCastNode(Stamp stamp, ValueNode input) {
-        super(stamp);
+        super(TYPE, stamp);
         this.input = input;
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 package com.oracle.graal.java;
 
 import static com.oracle.graal.api.code.TypeCheckHints.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 
 import java.util.*;
@@ -36,6 +37,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
@@ -73,18 +75,25 @@
     protected final MetaAccessProvider metaAccess;
 
     /**
+     * Specifies if the {@linkplain #getMethod() method} being parsed implements the semantics of
+     * another method (i.e., an intrinsic) or bytecode instruction (i.e., a snippet). substitution.
+     */
+    protected final boolean parsingReplacement;
+
+    /**
      * Meters the number of actual bytecodes parsed.
      */
     public static final DebugMetric BytecodesParsed = Debug.metric("BytecodesParsed");
 
-    public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
+    public AbstractBytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, boolean isReplacement) {
         this.graphBuilderConfig = graphBuilderConfig;
         this.optimisticOpts = optimisticOpts;
         this.metaAccess = metaAccess;
         this.stream = new BytecodeStream(method.getCode());
-        this.profilingInfo = method.getProfilingInfo();
+        this.profilingInfo = (graphBuilderConfig.getUseProfiling() ? method.getProfilingInfo() : null);
         this.constantPool = method.getConstantPool();
         this.method = method;
+        this.parsingReplacement = isReplacement;
         assert metaAccess != null;
     }
 
@@ -109,7 +118,7 @@
         if (kind == Kind.Object) {
             value = frameState.xpop();
             // astore and astore_<n> may be used to store a returnAddress (jsr)
-            assert value.getKind() == Kind.Object || value.getKind() == Kind.Int;
+            assert parsingReplacement || (value.getKind() == Kind.Object || value.getKind() == Kind.Int) : value + ":" + value.getKind();
         } else {
             value = frameState.pop(kind);
         }
@@ -563,7 +572,7 @@
     }
 
     private JavaTypeProfile getProfileForTypeCheck(ResolvedJavaType type) {
-        if (!optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
+        if (parsingReplacement || profilingInfo == null || !optimisticOpts.useTypeCheckHints() || !canHaveSubtype(type)) {
             return null;
         } else {
             return profilingInfo.getTypeProfile(bci());
@@ -604,9 +613,19 @@
 
     protected abstract T createNewInstance(ResolvedJavaType type, boolean fillContents);
 
+    @SuppressWarnings("unchecked")
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
+            ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
+            if (skippedExceptionTypes != null) {
+                for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
+                    if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) {
+                        append((T) new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
+                        return;
+                    }
+                }
+            }
             frameState.apush(append(createNewInstance((ResolvedJavaType) type, true)));
         } else {
             handleUnresolvedNewInstance(type);
@@ -688,7 +707,7 @@
         Kind kind = field.getKind();
         T receiver = frameState.apop();
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
             if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ValueNode) receiver, (ResolvedJavaField) field)) {
                 appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
             }
@@ -707,7 +726,7 @@
 
     protected void emitExplicitExceptions(T receiver, T outOfBoundsIndex) {
         assert receiver != null;
-        if (graphBuilderConfig.omitAllExceptionEdges() ||
+        if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null ||
                         (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
             return;
         }
@@ -737,7 +756,7 @@
     private void genGetStatic(JavaField field) {
         Kind kind = field.getKind();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
-            GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
             if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ResolvedJavaField) field)) {
                 appendOptimizedLoadField(kind, genLoadField(null, (ResolvedJavaField) field));
             }
@@ -786,7 +805,7 @@
     protected abstract void genRet(int localIndex);
 
     private double[] switchProbability(int numberOfCases, int bci) {
-        double[] prob = profilingInfo.getSwitchProbabilities(bci);
+        double[] prob = (profilingInfo == null ? null : profilingInfo.getSwitchProbabilities(bci));
         if (prob != null) {
             assert prob.length == numberOfCases;
         } else {
@@ -831,9 +850,9 @@
 
         Map<Integer, SuccessorInfo> bciToBlockSuccessorIndex = new HashMap<>();
         for (int i = 0; i < currentBlock.getSuccessorCount(); i++) {
-            assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessors().get(i).startBci);
-            if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessors().get(i).startBci)) {
-                bciToBlockSuccessorIndex.put(currentBlock.getSuccessors().get(i).startBci, new SuccessorInfo(i));
+            assert !bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci);
+            if (!bciToBlockSuccessorIndex.containsKey(currentBlock.getSuccessor(i).startBci)) {
+                bciToBlockSuccessorIndex.put(currentBlock.getSuccessor(i).startBci, new SuccessorInfo(i));
             }
         }
 
@@ -842,12 +861,13 @@
         int[] keySuccessors = new int[nofCases + 1];
         int deoptSuccessorIndex = -1;
         int nextSuccessorIndex = 0;
+        boolean constantValue = ((ValueNode) value).isConstant();
         for (int i = 0; i < nofCases + 1; i++) {
             if (i < nofCases) {
                 keys[i] = bs.keyAt(i);
             }
 
-            if (isNeverExecutedCode(keyProbabilities[i])) {
+            if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
                 if (deoptSuccessorIndex < 0) {
                     deoptSuccessorIndex = nextSuccessorIndex++;
                     actualSuccessors.add(null);
@@ -858,7 +878,7 @@
                 SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
                 if (info.actualIndex < 0) {
                     info.actualIndex = nextSuccessorIndex++;
-                    actualSuccessors.add(currentBlock.getSuccessors().get(info.blockIndex));
+                    actualSuccessors.add(currentBlock.getSuccessor(info.blockIndex));
                 }
                 keySuccessors[i] = info.actualIndex;
             }
@@ -890,6 +910,10 @@
     }
 
     protected double branchProbability() {
+        if (profilingInfo == null) {
+            return 0.5;
+        }
+        assert assertAtIfBytecode();
         double probability = profilingInfo.getBranchTakenProbability(bci());
         if (probability < 0) {
             assert probability == -1 : "invalid probability";
@@ -907,6 +931,31 @@
         return probability;
     }
 
+    private boolean assertAtIfBytecode() {
+        int bytecode = stream.currentBC();
+        switch (bytecode) {
+            case IFEQ:
+            case IFNE:
+            case IFLT:
+            case IFGE:
+            case IFGT:
+            case IFLE:
+            case IF_ICMPEQ:
+            case IF_ICMPNE:
+            case IF_ICMPLT:
+            case IF_ICMPGE:
+            case IF_ICMPGT:
+            case IF_ICMPLE:
+            case IF_ACMPEQ:
+            case IF_ACMPNE:
+            case IFNULL:
+            case IFNONNULL:
+                return true;
+        }
+        assert false : String.format("%x is not an if bytecode", bytecode);
+        return true;
+    }
+
     protected abstract void iterateBytecodesForBlock(BciBlock block);
 
     public final void processBytecode(int bci, int opcode) {
@@ -1137,10 +1186,11 @@
         return frameState;
     }
 
-    protected void traceInstruction(int bci, int opcode, boolean blockStart) {
+    protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
         if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_INSTRUCTIONS && Debug.isLogEnabled()) {
             traceInstructionHelper(bci, opcode, blockStart);
         }
+        return true;
     }
 
     private void traceInstructionHelper(int bci, int opcode, boolean blockStart) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
-import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
 
 public abstract class AbstractFrameStateBuilder<T extends KindProvider, S extends AbstractFrameStateBuilder<T, S>> {
 
@@ -37,15 +36,21 @@
     protected T[] lockedObjects;
 
     /**
+     * Specifies if asserting type checks are enabled.
+     */
+    protected final boolean checkTypes;
+
+    /**
      * @see BytecodeFrame#rethrowException
      */
     protected boolean rethrowException;
 
-    public AbstractFrameStateBuilder(ResolvedJavaMethod method) {
+    public AbstractFrameStateBuilder(ResolvedJavaMethod method, boolean checkTypes) {
         this.method = method;
         this.locals = allocateArray(method.getMaxLocals());
         this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
         this.lockedObjects = allocateArray(0);
+        this.checkTypes = checkTypes;
     }
 
     protected AbstractFrameStateBuilder(S other) {
@@ -55,6 +60,7 @@
         this.stack = other.stack.clone();
         this.lockedObjects = other.lockedObjects.length == 0 ? other.lockedObjects : other.lockedObjects.clone();
         this.rethrowException = other.rethrowException;
+        this.checkTypes = other.checkTypes;
 
         assert locals.length == method.getMaxLocals();
         assert stack.length == Math.max(1, method.getMaxStackSize());
@@ -172,8 +178,8 @@
     public T loadLocal(int i) {
         T x = locals[i];
         assert x != null : i;
-        assert x.getKind().getSlotCount() == 1 || locals[i + 1] == null;
-        assert i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1;
+        assert !checkTypes || (x.getKind().getSlotCount() == 1 || locals[i + 1] == null);
+        assert !checkTypes || (i == 0 || locals[i - 1] == null || locals[i - 1].getKind().getSlotCount() == 1);
         return x;
     }
 
@@ -185,7 +191,7 @@
      * @param x the instruction which produces the value for the local
      */
     public void storeLocal(int i, T x) {
-        assert x == null || x.getKind() != Kind.Void && x.getKind() != Kind.Illegal : "unexpected value: " + x;
+        assert x == null || !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
         locals[i] = x;
         if (x != null && x.getKind().needsTwoSlots()) {
             // if this is a double word, then kill i+1
@@ -212,7 +218,7 @@
      * @param x the instruction to push onto the stack
      */
     public void push(Kind kind, T x) {
-        assert x.getKind() != Kind.Void && x.getKind() != Kind.Illegal;
+        assert !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : x;
         xpush(assertKind(kind, x));
         if (kind.needsTwoSlots()) {
             xpush(null);
@@ -225,7 +231,7 @@
      * @param x the instruction to push onto the stack
      */
     public void xpush(T x) {
-        assert x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        assert !checkTypes || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
         stack[stackSize++] = x;
     }
 
@@ -369,7 +375,7 @@
                 newStackSize--;
                 assert stack[newStackSize].getKind().needsTwoSlots();
             } else {
-                assert stack[newStackSize].getKind().getSlotCount() == 1;
+                assert !checkTypes || (stack[newStackSize].getKind().getSlotCount() == 1);
             }
             result[i] = stack[newStackSize];
         }
@@ -405,7 +411,7 @@
     }
 
     private T assertKind(Kind kind, T x) {
-        assert x != null && x.getKind() == kind : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
+        assert x != null && (!checkTypes || x.getKind() == kind) : "kind=" + kind + ", value=" + x + ((x == null) ? "" : ", value.kind=" + x.getKind());
         return x;
     }
 
@@ -425,7 +431,7 @@
     }
 
     private T assertObject(T x) {
-        assert x != null && (x.getKind() == Kind.Object);
+        assert x != null && (!checkTypes || (x.getKind() == Kind.Object));
         return x;
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -31,10 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.nodes.*;
 
 /**
  * Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph
@@ -75,25 +72,17 @@
  */
 public final class BciBlockMapping {
 
-    public static class BciBlock extends AbstractBlockBase<BciBlock> implements Cloneable {
+    public static class BciBlock implements Cloneable {
 
+        protected int id;
         public int startBci;
         public int endBci;
         public boolean isExceptionEntry;
         public boolean isLoopHeader;
         public int loopId;
         public int loopEnd;
-
-        /**
-         * XXX to be removed - currently only used by baseline compiler.
-         */
-        public Loop<BciBlock> loop;
-        public boolean isLoopEnd;
-
-        private FixedWithNextNode firstInstruction;
-        private AbstractFrameStateBuilder<?, ?> entryState;
-        private FixedWithNextNode[] firstInstructionArray;
-        private AbstractFrameStateBuilder<?, ?>[] entryStateArray;
+        protected List<BciBlock> successors;
+        private int predecessorCount;
 
         private boolean visited;
         private boolean active;
@@ -128,6 +117,14 @@
             return null;
         }
 
+        public int getId() {
+            return id;
+        }
+
+        public int getPredecessorCount() {
+            return this.predecessorCount;
+        }
+
         public int numNormalSuccessors() {
             if (exceptionDispatchBlock() != null) {
                 return successors.size() - 1;
@@ -165,14 +162,6 @@
             return sb.toString();
         }
 
-        public Loop<BciBlock> getLoop() {
-            return loop;
-        }
-
-        public void setLoop(Loop<BciBlock> loop) {
-            this.loop = loop;
-        }
-
         public int getLoopDepth() {
             return Long.bitCount(loops);
         }
@@ -181,10 +170,6 @@
             return isLoopHeader;
         }
 
-        public boolean isLoopEnd() {
-            return isLoopEnd;
-        }
-
         public boolean isExceptionEntry() {
             return isExceptionEntry;
         }
@@ -258,7 +243,7 @@
             return jsrData;
         }
 
-        public void setEndsWithRet() {
+        void setEndsWithRet() {
             getOrCreateJSRData().endsWithRet = true;
         }
 
@@ -278,7 +263,7 @@
             }
         }
 
-        public void setRetSuccessor(BciBlock bciBlock) {
+        void setRetSuccessor(BciBlock bciBlock) {
             this.getOrCreateJSRData().retSuccessor = bciBlock;
         }
 
@@ -321,76 +306,40 @@
             }
         }
 
-        public void setJsrScope(JsrScope nextScope) {
+        void setJsrScope(JsrScope nextScope) {
             this.getOrCreateJSRData().jsrScope = nextScope;
         }
 
-        public void setJsrSuccessor(BciBlock clone) {
+        void setJsrSuccessor(BciBlock clone) {
             this.getOrCreateJSRData().jsrSuccessor = clone;
         }
 
-        public void setJsrReturnBci(int bci) {
+        void setJsrReturnBci(int bci) {
             this.getOrCreateJSRData().jsrReturnBci = bci;
         }
 
-        public FixedWithNextNode getFirstInstruction(int dimension) {
-            if (dimension == 0) {
-                return firstInstruction;
-            } else {
-                if (firstInstructionArray != null && dimension - 1 < firstInstructionArray.length) {
-                    return firstInstructionArray[dimension - 1];
-                } else {
-                    return null;
-                }
-            }
+        public int getSuccessorCount() {
+            return successors.size();
+        }
+
+        public List<BciBlock> getSuccessors() {
+            return successors;
         }
 
-        public void setFirstInstruction(int dimension, FixedWithNextNode firstInstruction) {
-            if (dimension == 0) {
-                this.firstInstruction = firstInstruction;
-            } else {
-                if (firstInstructionArray == null) {
-                    firstInstructionArray = new FixedWithNextNode[4];
-                }
-                if (dimension - 1 < firstInstructionArray.length) {
-                    // We are within bounds.
-                } else {
-                    // We are out of bounds.
-                    firstInstructionArray = Arrays.copyOf(firstInstructionArray, Math.max(firstInstructionArray.length * 2, dimension));
-                }
-
-                firstInstructionArray[dimension - 1] = firstInstruction;
-            }
+        void setId(int i) {
+            this.id = i;
         }
 
-        public AbstractFrameStateBuilder<?, ?> getEntryState(int dimension) {
-            if (dimension == 0) {
-                return entryState;
-            } else {
-                if (entryStateArray != null && dimension - 1 < entryStateArray.length) {
-                    return entryStateArray[dimension - 1];
-                } else {
-                    return null;
-                }
-            }
+        public void addSuccessor(BciBlock sux) {
+            successors.add(sux);
+            sux.predecessorCount++;
         }
 
-        public void setEntryState(int dimension, AbstractFrameStateBuilder<?, ?> entryState) {
-            if (dimension == 0) {
-                this.entryState = entryState;
-            } else {
-                if (entryStateArray == null) {
-                    entryStateArray = new AbstractFrameStateBuilder<?, ?>[4];
-                }
-                if (dimension - 1 < entryStateArray.length) {
-                    // We are within bounds.
-                } else {
-                    // We are out of bounds.
-                    entryStateArray = Arrays.copyOf(entryStateArray, Math.max(entryStateArray.length * 2, dimension));
-                }
-
-                entryStateArray[dimension - 1] = entryState;
+        public void clearSucccessors() {
+            for (BciBlock sux : successors) {
+                sux.predecessorCount--;
             }
+            successors.clear();
         }
     }
 
@@ -408,74 +357,61 @@
     private BciBlock[] blocks;
     public final ResolvedJavaMethod method;
     public boolean hasJsrBytecodes;
-    public BciBlock startBlock;
 
-    private final BytecodeStream stream;
     private final ExceptionHandler[] exceptionHandlers;
-    private BciBlock[] blockMap;
+    private BciBlock startBlock;
     private BciBlock[] loopHeaders;
 
     private static final int LOOP_HEADER_MAX_CAPACITY = Long.SIZE;
     private static final int LOOP_HEADER_INITIAL_CAPACITY = 4;
 
-    private final boolean doLivenessAnalysis;
-    public LocalLiveness liveness;
     private int blocksNotYetAssignedId;
-    private final boolean consecutiveLoopBlocks;
+    public int returnCount;
+    private int returnBci;
 
     /**
      * Creates a new BlockMap instance from bytecode of the given method .
      *
      * @param method the compiler interface method containing the code
      */
-    private BciBlockMapping(ResolvedJavaMethod method, boolean doLivenessAnalysis, boolean consecutiveLoopBlocks) {
-        this.doLivenessAnalysis = doLivenessAnalysis;
-        this.consecutiveLoopBlocks = consecutiveLoopBlocks;
+    private BciBlockMapping(ResolvedJavaMethod method) {
         this.method = method;
         this.exceptionHandlers = method.getExceptionHandlers();
-        this.stream = new BytecodeStream(method.getCode());
-        int codeSize = method.getCodeSize();
-        this.blockMap = new BciBlock[codeSize];
     }
 
     public BciBlock[] getBlocks() {
         return this.blocks;
     }
 
+    public int getReturnCount() {
+        return this.returnCount;
+    }
+
     /**
      * Builds the block map and conservative CFG and numbers blocks.
      */
-    public void build() {
-        makeExceptionEntries();
-        iterateOverBytecodes();
+    public void build(BytecodeStream stream) {
+        int codeSize = method.getCodeSize();
+        BciBlock[] blockMap = new BciBlock[codeSize];
+        makeExceptionEntries(blockMap);
+        iterateOverBytecodes(blockMap, stream);
         if (hasJsrBytecodes) {
             if (!SupportJsrBytecodes.getValue()) {
                 throw new JsrNotSupportedBailout("jsr/ret parsing disabled");
             }
-            createJsrAlternatives(blockMap[0]);
+            createJsrAlternatives(blockMap, blockMap[0]);
         }
         if (Debug.isLogEnabled()) {
-            this.log("Before BlockOrder");
+            this.log(blockMap, "Before BlockOrder");
         }
-        computeBlockOrder();
-        fixLoopBits();
-
-        startBlock = blockMap[0];
+        computeBlockOrder(blockMap);
+        fixLoopBits(blockMap);
 
         assert verify();
 
-        // Discard big arrays so that they can be GCed
-        blockMap = null;
+        startBlock = blockMap[0];
         if (Debug.isLogEnabled()) {
-            this.log("Before LivenessAnalysis");
-        }
-        if (doLivenessAnalysis) {
-            try (Scope s = Debug.scope("LivenessAnalysis")) {
-                liveness = method.getMaxLocals() <= 64 ? new SmallLocalLiveness() : new LargeLocalLiveness();
-                liveness.computeLiveness();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
+            this.log(blockMap, "Before LivenessAnalysis");
         }
     }
 
@@ -494,15 +430,15 @@
         return true;
     }
 
-    private void makeExceptionEntries() {
+    private void makeExceptionEntries(BciBlock[] blockMap) {
         // start basic blocks at all exception handler blocks and mark them as exception entries
         for (ExceptionHandler h : this.exceptionHandlers) {
-            BciBlock xhandler = makeBlock(h.getHandlerBCI());
+            BciBlock xhandler = makeBlock(blockMap, h.getHandlerBCI());
             xhandler.isExceptionEntry = true;
         }
     }
 
-    private void iterateOverBytecodes() {
+    private void iterateOverBytecodes(BciBlock[] blockMap, BytecodeStream stream) {
         // iterate over the bytecodes top to bottom.
         // mark the entrypoints of basic blocks and build lists of successors for
         // all bytecodes that end basic blocks (i.e. goto, ifs, switches, throw, jsr, returns, ret)
@@ -512,9 +448,9 @@
             int bci = stream.currentBCI();
 
             if (current == null || blockMap[bci] != null) {
-                BciBlock b = makeBlock(bci);
+                BciBlock b = makeBlock(blockMap, bci);
                 if (current != null) {
-                    addSuccessor(current.endBci, b);
+                    addSuccessor(blockMap, current.endBci, b);
                 }
                 current = b;
             }
@@ -528,14 +464,16 @@
                 case DRETURN: // fall through
                 case ARETURN: // fall through
                 case RETURN: {
+                    returnCount++;
                     current = null;
+                    returnBci = bci;
                     break;
                 }
                 case ATHROW: {
                     current = null;
-                    ExceptionDispatchBlock handler = handleExceptions(bci);
+                    ExceptionDispatchBlock handler = handleExceptions(blockMap, bci);
                     if (handler != null) {
-                        addSuccessor(bci, handler);
+                        addSuccessor(blockMap, bci, handler);
                     }
                     break;
                 }
@@ -556,24 +494,24 @@
                 case IFNULL:    // fall through
                 case IFNONNULL: {
                     current = null;
-                    addSuccessor(bci, makeBlock(stream.readBranchDest()));
-                    addSuccessor(bci, makeBlock(stream.nextBCI()));
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest()));
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI()));
                     break;
                 }
                 case GOTO:
                 case GOTO_W: {
                     current = null;
-                    addSuccessor(bci, makeBlock(stream.readBranchDest()));
+                    addSuccessor(blockMap, bci, makeBlock(blockMap, stream.readBranchDest()));
                     break;
                 }
                 case TABLESWITCH: {
                     current = null;
-                    addSwitchSuccessors(bci, new BytecodeTableSwitch(stream, bci));
+                    addSwitchSuccessors(blockMap, bci, new BytecodeTableSwitch(stream, bci));
                     break;
                 }
                 case LOOKUPSWITCH: {
                     current = null;
-                    addSwitchSuccessors(bci, new BytecodeLookupSwitch(stream, bci));
+                    addSwitchSuccessors(blockMap, bci, new BytecodeLookupSwitch(stream, bci));
                     break;
                 }
                 case JSR:
@@ -583,11 +521,11 @@
                     if (target == 0) {
                         throw new JsrNotSupportedBailout("jsr target bci 0 not allowed");
                     }
-                    BciBlock b1 = makeBlock(target);
+                    BciBlock b1 = makeBlock(blockMap, target);
                     current.setJsrSuccessor(b1);
                     current.setJsrReturnBci(stream.nextBCI());
                     current = null;
-                    addSuccessor(bci, b1);
+                    addSuccessor(blockMap, bci, b1);
                     break;
                 }
                 case RET: {
@@ -600,11 +538,11 @@
                 case INVOKESTATIC:
                 case INVOKEVIRTUAL:
                 case INVOKEDYNAMIC: {
-                    ExceptionDispatchBlock handler = handleExceptions(bci);
+                    ExceptionDispatchBlock handler = handleExceptions(blockMap, bci);
                     if (handler != null) {
                         current = null;
-                        addSuccessor(bci, makeBlock(stream.nextBCI()));
-                        addSuccessor(bci, handler);
+                        addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI()));
+                        addSuccessor(blockMap, bci, handler);
                     }
                     break;
                 }
@@ -626,11 +564,11 @@
                 case SALOAD:
                 case PUTFIELD:
                 case GETFIELD: {
-                    ExceptionDispatchBlock handler = handleExceptions(bci);
+                    ExceptionDispatchBlock handler = handleExceptions(blockMap, bci);
                     if (handler != null) {
                         current = null;
-                        addSuccessor(bci, makeBlock(stream.nextBCI()));
-                        addSuccessor(bci, handler);
+                        addSuccessor(blockMap, bci, makeBlock(blockMap, stream.nextBCI()));
+                        addSuccessor(blockMap, bci, handler);
                     }
                 }
             }
@@ -638,7 +576,7 @@
         }
     }
 
-    private BciBlock makeBlock(int startBci) {
+    private BciBlock makeBlock(BciBlock[] blockMap, int startBci) {
         BciBlock oldBlock = blockMap[startBci];
         if (oldBlock == null) {
             BciBlock newBlock = new BciBlock();
@@ -654,11 +592,13 @@
             blocksNotYetAssignedId++;
             newBlock.startBci = startBci;
             newBlock.endBci = oldBlock.endBci;
-            newBlock.getSuccessors().addAll(oldBlock.getSuccessors());
+            for (BciBlock oldSuccessor : oldBlock.getSuccessors()) {
+                newBlock.addSuccessor(oldSuccessor);
+            }
 
             oldBlock.endBci = startBci - 1;
-            oldBlock.getSuccessors().clear();
-            oldBlock.getSuccessors().add(newBlock);
+            oldBlock.clearSucccessors();
+            oldBlock.addSuccessor(newBlock);
 
             for (int i = startBci; i <= newBlock.endBci; i++) {
                 blockMap[i] = newBlock;
@@ -670,7 +610,7 @@
         }
     }
 
-    private void addSwitchSuccessors(int predBci, BytecodeSwitch bswitch) {
+    private void addSwitchSuccessors(BciBlock[] blockMap, int predBci, BytecodeSwitch bswitch) {
         // adds distinct targets to the successor list
         Collection<Integer> targets = new TreeSet<>();
         for (int i = 0; i < bswitch.numberOfCases(); i++) {
@@ -678,27 +618,27 @@
         }
         targets.add(bswitch.defaultTarget());
         for (int targetBci : targets) {
-            addSuccessor(predBci, makeBlock(targetBci));
+            addSuccessor(blockMap, predBci, makeBlock(blockMap, targetBci));
         }
     }
 
-    private void addSuccessor(int predBci, BciBlock sux) {
+    private static void addSuccessor(BciBlock[] blockMap, int predBci, BciBlock sux) {
         BciBlock predecessor = blockMap[predBci];
         if (sux.isExceptionEntry) {
             throw new BailoutException("Exception handler can be reached by both normal and exceptional control flow");
         }
-        predecessor.getSuccessors().add(sux);
+        predecessor.addSuccessor(sux);
     }
 
     private final ArrayList<BciBlock> jsrVisited = new ArrayList<>();
 
-    private void createJsrAlternatives(BciBlock block) {
+    private void createJsrAlternatives(BciBlock[] blockMap, BciBlock block) {
         jsrVisited.add(block);
         JsrScope scope = block.getJsrScope();
 
         if (block.endsWithRet()) {
             block.setRetSuccessor(blockMap[scope.nextReturnAddress()]);
-            block.getSuccessors().add(block.getRetSuccessor());
+            block.addSuccessor(block.getRetSuccessor());
             assert block.getRetSuccessor() != block.getJsrSuccessor();
         }
         Debug.log("JSR alternatives block %s  sux %s  jsrSux %s  retSux %s  jsrScope %s", block, block.getSuccessors(), block.getJsrSuccessor(), block.getRetSuccessor(), block.getJsrScope());
@@ -739,14 +679,14 @@
         }
         for (BciBlock successor : block.getSuccessors()) {
             if (!jsrVisited.contains(successor)) {
-                createJsrAlternatives(successor);
+                createJsrAlternatives(blockMap, successor);
             }
         }
     }
 
     private HashMap<ExceptionHandler, ExceptionDispatchBlock> initialExceptionDispatch = CollectionsFactory.newMap();
 
-    private ExceptionDispatchBlock handleExceptions(int bci) {
+    private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) {
         ExceptionDispatchBlock lastHandler = null;
 
         for (int i = exceptionHandlers.length - 1; i >= 0; i--) {
@@ -767,9 +707,9 @@
                     curHandler.endBci = -1;
                     curHandler.deoptBci = bci;
                     curHandler.handler = h;
-                    curHandler.getSuccessors().add(blockMap[h.getHandlerBCI()]);
+                    curHandler.addSuccessor(blockMap[h.getHandlerBCI()]);
                     if (lastHandler != null) {
-                        curHandler.getSuccessors().add(lastHandler);
+                        curHandler.addSuccessor(lastHandler);
                     }
                     exceptionDispatch.put(h, curHandler);
                 }
@@ -781,14 +721,14 @@
 
     private boolean loopChanges;
 
-    private void fixLoopBits() {
+    private void fixLoopBits(BciBlock[] blockMap) {
         do {
             loopChanges = false;
             for (BciBlock b : blocks) {
                 b.visited = false;
             }
 
-            long loop = fixLoopBits(blockMap[0]);
+            long loop = fixLoopBits(blockMap, blockMap[0]);
 
             if (loop != 0) {
                 // There is a path from a loop end to the method entry that does not pass the loop
@@ -801,7 +741,7 @@
         } while (loopChanges);
     }
 
-    private void computeBlockOrder() {
+    private void computeBlockOrder(BciBlock[] blockMap) {
         int maxBlocks = blocksNotYetAssignedId;
         this.blocks = new BciBlock[blocksNotYetAssignedId];
         long loop = computeBlockOrder(blockMap[0]);
@@ -813,17 +753,9 @@
             throw new BailoutException("Non-reducible loop");
         }
 
-        if (blocks[0] != null && this.nextLoop == 0) {
-            // No unreached blocks and no loops
-            for (int i = 0; i < blocks.length; ++i) {
-                blocks[i].setId(i);
-            }
-            return;
-        }
-
         // Purge null entries for unreached blocks and sort blocks such that loop bodies are always
         // consecutively in the array.
-        int blockCount = maxBlocks - blocksNotYetAssignedId;
+        int blockCount = maxBlocks - blocksNotYetAssignedId + 2;
         BciBlock[] newBlocks = new BciBlock[blockCount];
         int next = 0;
         for (int i = 0; i < blocks.length; ++i) {
@@ -831,11 +763,27 @@
             if (b != null) {
                 b.setId(next);
                 newBlocks[next++] = b;
-                if (consecutiveLoopBlocks && b.isLoopHeader) {
+                if (b.isLoopHeader) {
                     next = handleLoopHeader(newBlocks, next, i, b);
                 }
             }
         }
+
+        // Add return block.
+        BciBlock returnBlock = new BciBlock();
+        returnBlock.startBci = returnBci;
+        returnBlock.endBci = returnBci;
+        returnBlock.setId(newBlocks.length - 2);
+        newBlocks[newBlocks.length - 2] = returnBlock;
+
+        // Add unwind block.
+        ExceptionDispatchBlock unwindBlock = new ExceptionDispatchBlock();
+        unwindBlock.startBci = -1;
+        unwindBlock.endBci = -1;
+        unwindBlock.deoptBci = method.isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI;
+        unwindBlock.setId(newBlocks.length - 1);
+        newBlocks[newBlocks.length - 1] = unwindBlock;
+
         blocks = newBlocks;
     }
 
@@ -858,7 +806,7 @@
         return next;
     }
 
-    public void log(String name) {
+    public void log(BciBlock[] blockMap, String name) {
         if (Debug.isLogEnabled()) {
             String n = System.lineSeparator();
             StringBuilder sb = new StringBuilder(Debug.currentScope()).append("BlockMap ").append(name).append(" :");
@@ -976,7 +924,6 @@
             loops |= computeBlockOrder(successor);
             if (successor.active) {
                 // Reached block via backward branch.
-                block.isLoopEnd = true;
                 loops |= (1L << successor.loopId);
             }
         }
@@ -995,7 +942,7 @@
         return loops;
     }
 
-    private long fixLoopBits(BciBlock block) {
+    private long fixLoopBits(BciBlock[] blockMap, BciBlock block) {
         if (block.visited) {
             // Return cached loop information for this block.
             if (block.isLoopHeader) {
@@ -1009,7 +956,7 @@
         long loops = block.loops;
         for (BciBlock successor : block.getSuccessors()) {
             // Recursively process successors.
-            loops |= fixLoopBits(successor);
+            loops |= fixLoopBits(blockMap, successor);
         }
         if (block.loops != loops) {
             loopChanges = true;
@@ -1024,241 +971,9 @@
         return loops;
     }
 
-    /**
-     * Encapsulates the liveness calculation, so that subclasses for locals &le; 64 and locals &gt;
-     * 64 can be implemented.
-     */
-    public abstract class LocalLiveness {
-
-        private void computeLiveness() {
-            for (BciBlock block : blocks) {
-                computeLocalLiveness(block);
-            }
-
-            boolean changed;
-            int iteration = 0;
-            do {
-                Debug.log("Iteration %d", iteration);
-                changed = false;
-                for (int i = blocks.length - 1; i >= 0; i--) {
-                    BciBlock block = blocks[i];
-                    int blockID = block.getId();
-                    // log statements in IFs because debugLiveX creates a new String
-                    if (Debug.isLogEnabled()) {
-                        Debug.logv("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
-                                        debugLiveGen(blockID), debugLiveKill(blockID));
-                    }
-
-                    boolean blockChanged = (iteration == 0);
-                    if (block.getSuccessorCount() > 0) {
-                        int oldCardinality = liveOutCardinality(blockID);
-                        for (BciBlock sux : block.getSuccessors()) {
-                            if (Debug.isLogEnabled()) {
-                                Debug.log("    Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId()));
-                            }
-                            propagateLiveness(blockID, sux.getId());
-                        }
-                        blockChanged |= (oldCardinality != liveOutCardinality(blockID));
-                    }
-
-                    if (blockChanged) {
-                        updateLiveness(blockID);
-                        if (Debug.isLogEnabled()) {
-                            Debug.logv("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
-                                            debugLiveGen(blockID), debugLiveKill(blockID));
-                        }
-                    }
-                    changed |= blockChanged;
-                }
-                iteration++;
-            } while (changed);
-        }
-
-        /**
-         * Returns whether the local is live at the beginning of the given block.
-         */
-        public abstract boolean localIsLiveIn(BciBlock block, int local);
-
-        /**
-         * Returns whether the local is set in the given loop.
-         */
-        public abstract boolean localIsChangedInLoop(int loopId, int local);
-
-        /**
-         * Returns whether the local is live at the end of the given block.
-         */
-        public abstract boolean localIsLiveOut(BciBlock block, int local);
-
-        /**
-         * Returns a string representation of the liveIn values of the given block.
-         */
-        protected abstract String debugLiveIn(int blockID);
-
-        /**
-         * Returns a string representation of the liveOut values of the given block.
-         */
-        protected abstract String debugLiveOut(int blockID);
-
-        /**
-         * Returns a string representation of the liveGen values of the given block.
-         */
-        protected abstract String debugLiveGen(int blockID);
-
-        /**
-         * Returns a string representation of the liveKill values of the given block.
-         */
-        protected abstract String debugLiveKill(int blockID);
-
-        /**
-         * Returns the number of live locals at the end of the given block.
-         */
-        protected abstract int liveOutCardinality(int blockID);
-
-        /**
-         * Adds all locals the are in the liveIn of the successor to the liveOut of the block.
-         */
-        protected abstract void propagateLiveness(int blockID, int successorID);
-
-        /**
-         * Calculates a new liveIn for the given block from liveOut, liveKill and liveGen.
-         */
-        protected abstract void updateLiveness(int blockID);
-
-        /**
-         * Adds the local to liveGen if it wasn't already killed in this block.
-         */
-        protected abstract void loadOne(int blockID, int local);
-
-        /**
-         * Add this local to liveKill if it wasn't already generated in this block.
-         */
-        protected abstract void storeOne(int blockID, int local);
-
-        private void computeLocalLiveness(BciBlock block) {
-            if (block.startBci < 0 || block.endBci < 0) {
-                return;
-            }
-            int blockID = block.getId();
-            int localIndex;
-            stream.setBCI(block.startBci);
-            while (stream.currentBCI() <= block.endBci) {
-                switch (stream.currentBC()) {
-                    case LLOAD:
-                    case DLOAD:
-                        loadTwo(blockID, stream.readLocalIndex());
-                        break;
-                    case LLOAD_0:
-                    case DLOAD_0:
-                        loadTwo(blockID, 0);
-                        break;
-                    case LLOAD_1:
-                    case DLOAD_1:
-                        loadTwo(blockID, 1);
-                        break;
-                    case LLOAD_2:
-                    case DLOAD_2:
-                        loadTwo(blockID, 2);
-                        break;
-                    case LLOAD_3:
-                    case DLOAD_3:
-                        loadTwo(blockID, 3);
-                        break;
-                    case IINC:
-                        localIndex = stream.readLocalIndex();
-                        loadOne(blockID, localIndex);
-                        storeOne(blockID, localIndex);
-                        break;
-                    case ILOAD:
-                    case FLOAD:
-                    case ALOAD:
-                    case RET:
-                        loadOne(blockID, stream.readLocalIndex());
-                        break;
-                    case ILOAD_0:
-                    case FLOAD_0:
-                    case ALOAD_0:
-                        loadOne(blockID, 0);
-                        break;
-                    case ILOAD_1:
-                    case FLOAD_1:
-                    case ALOAD_1:
-                        loadOne(blockID, 1);
-                        break;
-                    case ILOAD_2:
-                    case FLOAD_2:
-                    case ALOAD_2:
-                        loadOne(blockID, 2);
-                        break;
-                    case ILOAD_3:
-                    case FLOAD_3:
-                    case ALOAD_3:
-                        loadOne(blockID, 3);
-                        break;
-
-                    case LSTORE:
-                    case DSTORE:
-                        storeTwo(blockID, stream.readLocalIndex());
-                        break;
-                    case LSTORE_0:
-                    case DSTORE_0:
-                        storeTwo(blockID, 0);
-                        break;
-                    case LSTORE_1:
-                    case DSTORE_1:
-                        storeTwo(blockID, 1);
-                        break;
-                    case LSTORE_2:
-                    case DSTORE_2:
-                        storeTwo(blockID, 2);
-                        break;
-                    case LSTORE_3:
-                    case DSTORE_3:
-                        storeTwo(blockID, 3);
-                        break;
-                    case ISTORE:
-                    case FSTORE:
-                    case ASTORE:
-                        storeOne(blockID, stream.readLocalIndex());
-                        break;
-                    case ISTORE_0:
-                    case FSTORE_0:
-                    case ASTORE_0:
-                        storeOne(blockID, 0);
-                        break;
-                    case ISTORE_1:
-                    case FSTORE_1:
-                    case ASTORE_1:
-                        storeOne(blockID, 1);
-                        break;
-                    case ISTORE_2:
-                    case FSTORE_2:
-                    case ASTORE_2:
-                        storeOne(blockID, 2);
-                        break;
-                    case ISTORE_3:
-                    case FSTORE_3:
-                    case ASTORE_3:
-                        storeOne(blockID, 3);
-                        break;
-                }
-                stream.next();
-            }
-        }
-
-        private void loadTwo(int blockID, int local) {
-            loadOne(blockID, local);
-            loadOne(blockID, local + 1);
-        }
-
-        private void storeTwo(int blockID, int local) {
-            storeOne(blockID, local);
-            storeOne(blockID, local + 1);
-        }
-    }
-
-    public static BciBlockMapping create(ResolvedJavaMethod method, boolean doLivenessAnalysis, boolean consecutiveLoopBlocks) {
-        BciBlockMapping map = new BciBlockMapping(method, doLivenessAnalysis, consecutiveLoopBlocks);
-        map.build();
+    public static BciBlockMapping create(BytecodeStream stream, ResolvedJavaMethod method) {
+        BciBlockMapping map = new BciBlockMapping(method);
+        map.build(stream);
         if (Debug.isDumpEnabled()) {
             Debug.dump(map, method.format("After block building %f %R %H.%n(%P)"));
         }
@@ -1266,228 +981,27 @@
         return map;
     }
 
-    public final class SmallLocalLiveness extends LocalLiveness {
-        /*
-         * local n is represented by the bit accessible as (1 << n)
-         */
-
-        private final long[] localsLiveIn;
-        private final long[] localsLiveOut;
-        private final long[] localsLiveGen;
-        private final long[] localsLiveKill;
-        private final long[] localsChangedInLoop;
-
-        public SmallLocalLiveness() {
-            int blockSize = blocks.length;
-            localsLiveIn = new long[blockSize];
-            localsLiveOut = new long[blockSize];
-            localsLiveGen = new long[blockSize];
-            localsLiveKill = new long[blockSize];
-            localsChangedInLoop = new long[BciBlockMapping.this.nextLoop];
-        }
-
-        private String debugString(long value) {
-            StringBuilder str = new StringBuilder("{");
-            long current = value;
-            for (int i = 0; i < method.getMaxLocals(); i++) {
-                if ((current & 1L) == 1L) {
-                    if (str.length() > 1) {
-                        str.append(", ");
-                    }
-                    str.append(i);
-                }
-                current >>= 1;
-            }
-            return str.append('}').toString();
-        }
-
-        @Override
-        protected String debugLiveIn(int blockID) {
-            return debugString(localsLiveIn[blockID]);
-        }
-
-        @Override
-        protected String debugLiveOut(int blockID) {
-            return debugString(localsLiveOut[blockID]);
-        }
-
-        @Override
-        protected String debugLiveGen(int blockID) {
-            return debugString(localsLiveGen[blockID]);
-        }
-
-        @Override
-        protected String debugLiveKill(int blockID) {
-            return debugString(localsLiveKill[blockID]);
-        }
-
-        @Override
-        protected int liveOutCardinality(int blockID) {
-            return Long.bitCount(localsLiveOut[blockID]);
-        }
-
-        @Override
-        protected void propagateLiveness(int blockID, int successorID) {
-            localsLiveOut[blockID] |= localsLiveIn[successorID];
-        }
-
-        @Override
-        protected void updateLiveness(int blockID) {
-            localsLiveIn[blockID] = (localsLiveOut[blockID] & ~localsLiveKill[blockID]) | localsLiveGen[blockID];
-        }
-
-        @Override
-        protected void loadOne(int blockID, int local) {
-            long bit = 1L << local;
-            if ((localsLiveKill[blockID] & bit) == 0L) {
-                localsLiveGen[blockID] |= bit;
-            }
-        }
-
-        @Override
-        protected void storeOne(int blockID, int local) {
-            long bit = 1L << local;
-            if ((localsLiveGen[blockID] & bit) == 0L) {
-                localsLiveKill[blockID] |= bit;
-            }
-
-            BciBlock block = blocks[blockID];
-            long tmp = block.loops;
-            int pos = 0;
-            while (tmp != 0) {
-                if ((tmp & 1L) == 1L) {
-                    this.localsChangedInLoop[pos] |= bit;
-                }
-                tmp >>= 1;
-                ++pos;
-            }
-        }
-
-        @Override
-        public boolean localIsLiveIn(BciBlock block, int local) {
-            int blockID = block.getId();
-            return blockID >= Integer.MAX_VALUE ? false : (localsLiveIn[blockID] & (1L << local)) != 0L;
-        }
-
-        @Override
-        public boolean localIsLiveOut(BciBlock block, int local) {
-            int blockID = block.getId();
-            return blockID >= Integer.MAX_VALUE ? false : (localsLiveOut[blockID] & (1L << local)) != 0L;
-        }
-
-        @Override
-        public boolean localIsChangedInLoop(int loopId, int local) {
-            return (localsChangedInLoop[loopId] & (1L << local)) != 0L;
-        }
-    }
-
-    public final class LargeLocalLiveness extends LocalLiveness {
-        private BitSet[] localsLiveIn;
-        private BitSet[] localsLiveOut;
-        private BitSet[] localsLiveGen;
-        private BitSet[] localsLiveKill;
-        private BitSet[] localsChangedInLoop;
-
-        public LargeLocalLiveness() {
-            int blocksSize = blocks.length;
-            localsLiveIn = new BitSet[blocksSize];
-            localsLiveOut = new BitSet[blocksSize];
-            localsLiveGen = new BitSet[blocksSize];
-            localsLiveKill = new BitSet[blocksSize];
-            int maxLocals = method.getMaxLocals();
-            for (int i = 0; i < blocksSize; i++) {
-                localsLiveIn[i] = new BitSet(maxLocals);
-                localsLiveOut[i] = new BitSet(maxLocals);
-                localsLiveGen[i] = new BitSet(maxLocals);
-                localsLiveKill[i] = new BitSet(maxLocals);
-            }
-            localsChangedInLoop = new BitSet[nextLoop];
-            for (int i = 0; i < nextLoop; ++i) {
-                localsChangedInLoop[i] = new BitSet(maxLocals);
-            }
-        }
-
-        @Override
-        protected String debugLiveIn(int blockID) {
-            return localsLiveIn[blockID].toString();
-        }
-
-        @Override
-        protected String debugLiveOut(int blockID) {
-            return localsLiveOut[blockID].toString();
-        }
-
-        @Override
-        protected String debugLiveGen(int blockID) {
-            return localsLiveGen[blockID].toString();
-        }
-
-        @Override
-        protected String debugLiveKill(int blockID) {
-            return localsLiveKill[blockID].toString();
-        }
-
-        @Override
-        protected int liveOutCardinality(int blockID) {
-            return localsLiveOut[blockID].cardinality();
-        }
-
-        @Override
-        protected void propagateLiveness(int blockID, int successorID) {
-            localsLiveOut[blockID].or(localsLiveIn[successorID]);
-        }
-
-        @Override
-        protected void updateLiveness(int blockID) {
-            BitSet liveIn = localsLiveIn[blockID];
-            liveIn.clear();
-            liveIn.or(localsLiveOut[blockID]);
-            liveIn.andNot(localsLiveKill[blockID]);
-            liveIn.or(localsLiveGen[blockID]);
-        }
-
-        @Override
-        protected void loadOne(int blockID, int local) {
-            if (!localsLiveKill[blockID].get(local)) {
-                localsLiveGen[blockID].set(local);
-            }
-        }
-
-        @Override
-        protected void storeOne(int blockID, int local) {
-            if (!localsLiveGen[blockID].get(local)) {
-                localsLiveKill[blockID].set(local);
-            }
-
-            BciBlock block = blocks[blockID];
-            long tmp = block.loops;
-            int pos = 0;
-            while (tmp != 0) {
-                if ((tmp & 1L) == 1L) {
-                    this.localsChangedInLoop[pos].set(local);
-                }
-                tmp >>= 1;
-                ++pos;
-            }
-        }
-
-        @Override
-        public boolean localIsLiveIn(BciBlock block, int local) {
-            return block.getId() >= Integer.MAX_VALUE ? true : localsLiveIn[block.getId()].get(local);
-        }
-
-        @Override
-        public boolean localIsLiveOut(BciBlock block, int local) {
-            return block.getId() >= Integer.MAX_VALUE ? true : localsLiveOut[block.getId()].get(local);
-        }
-
-        @Override
-        public boolean localIsChangedInLoop(int loopId, int local) {
-            return localsChangedInLoop[loopId].get(local);
-        }
-    }
-
     public BciBlock[] getLoopHeaders() {
         return loopHeaders;
     }
+
+    public BciBlock getStartBlock() {
+        return startBlock;
+    }
+
+    public BciBlock getReturnBlock() {
+        return blocks[blocks.length - 2];
+    }
+
+    public ExceptionDispatchBlock getUnwindBlock() {
+        return (ExceptionDispatchBlock) blocks[blocks.length - 1];
+    }
+
+    public int getLoopCount() {
+        return nextLoop;
+    }
+
+    public int getBlockCount() {
+        return blocks.length;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java	Sat Feb 21 19:55:33 2015 +0100
@@ -62,10 +62,11 @@
         Map<LoopExitNode, Double> exitStates = ReentrantNodeIterator.processLoop(this, loop, 1D).exitStates;
 
         double exitProbability = exitStates.values().stream().mapToDouble(d -> d).sum();
-        assert exitProbability <= 1D && exitProbability >= 0D;
+        exitProbability = Math.min(1D, exitProbability);
         if (exitProbability < MIN_PROBABILITY) {
             exitProbability = MIN_PROBABILITY;
         }
+        assert exitProbability <= 1D && exitProbability >= 0D;
         double loopFrequency = 1D / exitProbability;
         loop.setLoopFrequency(loopFrequency);
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultGraphBuilderPlugins.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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 java.util.*;
-import java.util.stream.*;
-
-import com.oracle.graal.api.meta.*;
-
-/**
- * Default implementation of {@link GraphBuilderPlugins} that uses a map.
- */
-public class DefaultGraphBuilderPlugins implements GraphBuilderPlugins {
-
-    private final Map<ResolvedJavaMethod, InvocationPlugin> plugins = new HashMap<>();
-
-    /**
-     * Registers an invocation plugin for a given method. There must be no plugin currently
-     * registered for {@code method}.
-     */
-    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
-        assert InvocationPluginChecker.check(method, plugin);
-        GraphBuilderPlugin oldValue = plugins.put(method, plugin);
-        // System.out.println("registered: " + plugin);
-        assert oldValue == null;
-    }
-
-    /**
-     * Gets the plugin for a given method.
-     *
-     * @param method the method to lookup
-     * @return the plugin associated with {@code method} or {@code null} if none exists
-     */
-    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
-        return plugins.get(method);
-    }
-
-    @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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/DefaultSuitesProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,30 +22,48 @@
  */
 package com.oracle.graal.java;
 
-import java.util.function.*;
-
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
+import com.oracle.graal.options.DerivedOptionValue.OptionSupplier;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.tiers.*;
 
-public class DefaultSuitesProvider implements SuitesProvider, Supplier<Suites> {
+public class DefaultSuitesProvider implements SuitesProvider {
 
     private final DerivedOptionValue<Suites> defaultSuites;
     private final PhaseSuite<HighTierContext> defaultGraphBuilderSuite;
+    private final DerivedOptionValue<LIRSuites> defaultLIRSuites;
+
+    private class SuitesSupplier implements OptionSupplier<Suites> {
+
+        private static final long serialVersionUID = 2677805381215454728L;
+
+        public Suites get() {
+            return createSuites();
+        }
+
+    }
+
+    private class LIRSuitesSupplier implements OptionSupplier<LIRSuites> {
+
+        private static final long serialVersionUID = 312070237227476252L;
+
+        public LIRSuites get() {
+            return createLIRSuites();
+        }
+
+    }
 
     public DefaultSuitesProvider() {
         this.defaultGraphBuilderSuite = createGraphBuilderSuite();
-        this.defaultSuites = new DerivedOptionValue<>(this::createSuites);
+        this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
+        this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
 
     public Suites getDefaultSuites() {
         return defaultSuites.getValue();
     }
 
-    public Suites get() {
-        return createSuites();
-    }
-
     public Suites createSuites() {
         return Suites.createDefaultSuites();
     }
@@ -60,4 +78,12 @@
         return suite;
     }
 
+    public LIRSuites getDefaultLIRSuites() {
+        return defaultLIRSuites.getValue();
+    }
+
+    public LIRSuites createLIRSuites() {
+        return Suites.createDefaultLIRSuites();
+    }
+
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraalDirectivePlugins.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,103 +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.java;
-
-import com.oracle.graal.api.directives.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.debug.*;
-import com.oracle.graal.nodes.extended.*;
-
-public class GraalDirectivePlugins {
-
-    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, GraalDirectives.class);
-        r.register0("deoptimize", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
-                return true;
-            }
-        });
-
-        r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
-                return true;
-            }
-        });
-
-        r.register0("inCompiledCode", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.push(Kind.Int, builder.append(ConstantNode.forInt(1)));
-                return true;
-            }
-        });
-
-        r.register0("controlFlowAnchor", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder) {
-                builder.append(new ControlFlowAnchorNode());
-                return true;
-            }
-        });
-
-        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
-                builder.push(Kind.Int, builder.append(new BranchProbabilityNode(probability, condition)));
-                return true;
-            }
-        });
-
-        InvocationPlugin blackholePlugin = new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                builder.append(new BlackholeNode(value));
-                return true;
-            }
-        };
-
-        for (Kind kind : Kind.values()) {
-            Class<?> cls = null;
-            switch (kind) {
-                case Object:
-                    cls = Object.class;
-                    break;
-                case Void:
-                case Illegal:
-                    continue;
-                default:
-                    cls = kind.toJavaClass();
-            }
-
-            r.register1("blackhole", cls, blackholePlugin);
-
-            final Kind stackKind = kind.getStackKind();
-            r.register1("opaque", cls, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext builder, ValueNode value) {
-                    builder.push(stackKind, builder.append(new OpaqueNode(value)));
-                    return true;
-                }
-            });
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,11 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.java.GraphBuilderPlugin.AnnotatedInvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.LoopExplosionPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.nodes.*;
 
 public class GraphBuilderConfiguration {
@@ -36,10 +41,13 @@
     private final ResolvedJavaType[] skippedExceptionTypes;
     private final DebugInfoMode debugInfoMode;
     private final boolean doLivenessAnalysis;
-    private GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin;
-    private GraphBuilderPlugins.ParameterPlugin parameterPlugin;
-    private GraphBuilderPlugins.InlineInvokePlugin inlineInvokePlugin;
-    private GraphBuilderPlugins.LoopExplosionPlugin loopExplosionPlugin;
+    private InvocationPlugins invocationPlugins = new InvocationPlugins();
+    private LoadFieldPlugin loadFieldPlugin;
+    private ParameterPlugin parameterPlugin;
+    private InlineInvokePlugin inlineInvokePlugin;
+    private AnnotatedInvocationPlugin annotatedInvocationPlugin;
+    private LoopExplosionPlugin loopExplosionPlugin;
+    private boolean useProfiling;
 
     public static enum DebugInfoMode {
         SafePointsOnly,
@@ -71,14 +79,24 @@
         this.debugInfoMode = debugInfoMode;
         this.skippedExceptionTypes = skippedExceptionTypes;
         this.doLivenessAnalysis = doLivenessAnalysis;
+        this.useProfiling = true;
     }
 
     public GraphBuilderConfiguration copy() {
         GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis);
-        result.loadFieldPlugin = loadFieldPlugin;
+        result.useProfiling = useProfiling;
+        result.copyPluginsFrom(this);
         return result;
     }
 
+    public boolean getUseProfiling() {
+        return useProfiling;
+    }
+
+    public void setUseProfiling(boolean b) {
+        this.useProfiling = b;
+    }
+
     public GraphBuilderConfiguration withSkippedExceptionTypes(ResolvedJavaType[] newSkippedExceptionTypes) {
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, newSkippedExceptionTypes, doLivenessAnalysis);
     }
@@ -96,12 +114,24 @@
         return new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, newLivenessAnalysis);
     }
 
-    public GraphBuilderPlugins.LoadFieldPlugin getLoadFieldPlugin() {
+    public InvocationPlugins getInvocationPlugins() {
+        return invocationPlugins;
+    }
+
+    public AnnotatedInvocationPlugin getAnnotatedInvocationPlugin() {
+        return annotatedInvocationPlugin;
+    }
+
+    public void setAnnotatedInvocationPlugin(AnnotatedInvocationPlugin plugin) {
+        this.annotatedInvocationPlugin = plugin;
+    }
+
+    public LoadFieldPlugin getLoadFieldPlugin() {
         return loadFieldPlugin;
     }
 
-    public void setLoadFieldPlugin(GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin) {
-        this.loadFieldPlugin = loadFieldPlugin;
+    public void setLoadFieldPlugin(LoadFieldPlugin plugin) {
+        this.loadFieldPlugin = plugin;
     }
 
     public ResolvedJavaType[] getSkippedExceptionTypes() {
@@ -153,27 +183,37 @@
         return eagerResolving;
     }
 
-    public GraphBuilderPlugins.ParameterPlugin getParameterPlugin() {
+    public ParameterPlugin getParameterPlugin() {
         return parameterPlugin;
     }
 
-    public void setParameterPlugin(GraphBuilderPlugins.ParameterPlugin parameterPlugin) {
-        this.parameterPlugin = parameterPlugin;
+    public void setParameterPlugin(ParameterPlugin plugin) {
+        this.parameterPlugin = plugin;
     }
 
-    public GraphBuilderPlugins.InlineInvokePlugin getInlineInvokePlugin() {
+    public InlineInvokePlugin getInlineInvokePlugin() {
         return inlineInvokePlugin;
     }
 
-    public void setInlineInvokePlugin(GraphBuilderPlugins.InlineInvokePlugin inlineInvokePlugin) {
-        this.inlineInvokePlugin = inlineInvokePlugin;
+    public void setInlineInvokePlugin(InlineInvokePlugin plugin) {
+        this.inlineInvokePlugin = plugin;
     }
 
-    public GraphBuilderPlugins.LoopExplosionPlugin getLoopExplosionPlugin() {
+    public LoopExplosionPlugin getLoopExplosionPlugin() {
         return loopExplosionPlugin;
     }
 
-    public void setLoopExplosionPlugin(GraphBuilderPlugins.LoopExplosionPlugin loopExplosionPlugin) {
-        this.loopExplosionPlugin = loopExplosionPlugin;
+    public void setLoopExplosionPlugin(LoopExplosionPlugin plugin) {
+        this.loopExplosionPlugin = plugin;
+    }
+
+    public GraphBuilderConfiguration copyPluginsFrom(GraphBuilderConfiguration other) {
+        this.invocationPlugins.updateFrom(other.getInvocationPlugins());
+        this.parameterPlugin = other.parameterPlugin;
+        this.loadFieldPlugin = other.loadFieldPlugin;
+        this.inlineInvokePlugin = other.inlineInvokePlugin;
+        this.loopExplosionPlugin = other.loopExplosionPlugin;
+        this.annotatedInvocationPlugin = other.annotatedInvocationPlugin;
+        return this;
     }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,8 +24,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -41,6 +43,8 @@
 
     <T extends FloatingNode> T append(T value);
 
+    <T extends ValueNode> T append(T value);
+
     StampProvider getStampProvider();
 
     MetaAccessProvider getMetaAccess();
@@ -49,8 +53,17 @@
 
     ConstantReflectionProvider getConstantReflection();
 
+    SnippetReflectionProvider getSnippetReflection();
+
     void push(Kind kind, ValueNode value);
 
+    StructuredGraph getGraph();
+
+    /**
+     * Determines if the graph builder is parsing a snippet or method substitution.
+     */
+    boolean parsingReplacement();
+
     /**
      * @see GuardingPiNode#nullCheckedValue(ValueNode)
      */
@@ -61,4 +74,8 @@
         }
         return nonNullValue;
     }
+
+    GuardingNode getCurrentBlockGuard();
+
+    BailoutException bailout(String string);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,27 +26,32 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+import static com.oracle.graal.nodes.StructuredGraph.*;
+import static java.lang.String.*;
 
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.meta.ProfilingInfo.TriState;
+import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.*;
 import com.oracle.graal.graph.Graph.Mark;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
-import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
-import com.oracle.graal.java.GraphBuilderPlugins.InlineInvokePlugin;
-import com.oracle.graal.java.GraphBuilderPlugins.InvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugins.LoopExplosionPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.AnnotatedInvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.InlineInvokePlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.LoopExplosionPlugin;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.calc.*;
@@ -64,31 +69,20 @@
 public class GraphBuilderPhase extends BasePhase<HighTierContext> {
 
     private final GraphBuilderConfiguration graphBuilderConfig;
-    private final GraphBuilderPlugins graphBuilderPlugins;
 
     public GraphBuilderPhase(GraphBuilderConfiguration config) {
-        this(config, new DefaultGraphBuilderPlugins());
-    }
-
-    public GraphBuilderPhase(GraphBuilderConfiguration config, GraphBuilderPlugins graphBuilderPlugins) {
         this.graphBuilderConfig = config;
-        this.graphBuilderPlugins = graphBuilderPlugins;
     }
 
     @Override
     protected void run(StructuredGraph graph, HighTierContext context) {
-        new Instance(context.getMetaAccess(), context.getStampProvider(), context.getAssumptions(), context.getConstantReflection(), graphBuilderConfig, graphBuilderPlugins,
-                        context.getOptimisticOptimizations()).run(graph);
+        new Instance(context.getMetaAccess(), context.getStampProvider(), null, context.getConstantReflection(), graphBuilderConfig, context.getOptimisticOptimizations()).run(graph);
     }
 
     public GraphBuilderConfiguration getGraphBuilderConfig() {
         return graphBuilderConfig;
     }
 
-    public GraphBuilderPlugins getGraphBuilderPlugins() {
-        return graphBuilderPlugins;
-    }
-
     public static class Instance extends Phase {
 
         protected StructuredGraph currentGraph;
@@ -98,11 +92,10 @@
         private ResolvedJavaMethod rootMethod;
 
         private final GraphBuilderConfiguration graphBuilderConfig;
-        private final GraphBuilderPlugins graphBuilderPlugins;
         private final OptimisticOptimizations optimisticOpts;
         private final StampProvider stampProvider;
-        private final Assumptions assumptions;
         private final ConstantReflectionProvider constantReflection;
+        private final SnippetReflectionProvider snippetReflectionProvider;
 
         /**
          * Gets the graph being processed by this builder.
@@ -111,21 +104,20 @@
             return currentGraph;
         }
 
-        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, Assumptions assumptions, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) {
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection,
+                        GraphBuilderConfiguration graphBuilderConfig, 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, constantReflection, graphBuilderConfig, null, optimisticOpts);
+        public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
+                        OptimisticOptimizations optimisticOpts) {
+            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts);
         }
 
         @Override
@@ -135,17 +127,17 @@
             int entryBCI = graph.getEntryBCI();
             assert method.getCode() != null : "method must contain bytecodes: " + method;
             this.currentGraph = graph;
-            HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, null);
+            HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(method, graph, true, null);
             frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving(), this.graphBuilderConfig.getParameterPlugin());
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
-                BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI);
+                BytecodeParser parser = new BytecodeParser(metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, false);
                 parser.build(0, graph.start(), frameState);
 
                 parser.connectLoopEndToBegin();
 
                 // remove dead parameters
-                for (ParameterNode param : currentGraph.getNodes(ParameterNode.class)) {
+                for (ParameterNode param : currentGraph.getNodes(ParameterNode.TYPE)) {
                     if (param.hasNoUsages()) {
                         assert param.inputs().isEmpty();
                         param.safeDelete();
@@ -182,7 +174,7 @@
 
         public class BytecodeParser extends AbstractBytecodeParser<ValueNode, HIRFrameStateBuilder> implements GraphBuilderContext {
 
-            private BciBlock[] loopHeaders;
+            private BciBlockMapping blockMap;
             private LocalLiveness liveness;
             protected final int entryBCI;
             private int currentDepth;
@@ -192,8 +184,6 @@
             private int currentLineNumber;
 
             private ValueNode methodSynchronizedObject;
-            private ExceptionDispatchBlock unwindBlock;
-            private BciBlock returnBlock;
 
             private ValueNode returnValue;
             private FixedWithNextNode beforeReturnNode;
@@ -204,9 +194,21 @@
             private final boolean explodeLoops;
             private Stack<ExplodedLoopContext> explodeLoopsContext;
             private int nextPeelIteration = 1;
+            private boolean controlFlowSplit;
 
-            public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI) {
-                super(metaAccess, method, graphBuilderConfig, optimisticOpts);
+            private FixedWithNextNode[] firstInstructionArray;
+            private HIRFrameStateBuilder[] entryStateArray;
+            private FixedWithNextNode[][] firstInstructionMatrix;
+            private HIRFrameStateBuilder[][] entryStateMatrix;
+
+            /**
+             * @param isReplacement specifies if this object is being used to parse a method that
+             *            implements the semantics of another method (i.e., an intrinsic) or
+             *            bytecode instruction (i.e., a snippet)
+             */
+            public BytecodeParser(MetaAccessProvider metaAccess, ResolvedJavaMethod method, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, int entryBCI,
+                            boolean isReplacement) {
+                super(metaAccess, method, graphBuilderConfig, optimisticOpts, isReplacement);
                 this.entryBCI = entryBCI;
 
                 if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
@@ -240,7 +242,7 @@
 
             protected void build(int depth, FixedWithNextNode startInstruction, HIRFrameStateBuilder startFrameState) {
                 this.currentDepth = depth;
-                if (PrintProfilingInformation.getValue()) {
+                if (PrintProfilingInformation.getValue() && profilingInfo != null) {
                     TTY.println("Profiling info for " + method.format("%H.%n(%p)"));
                     TTY.println(MetaUtil.indent(profilingInfo.toString(method, CodeUtil.NEW_LINE), "  "));
                 }
@@ -248,19 +250,31 @@
                 try (Indent indent = Debug.logAndIndent("build graph for %s", method)) {
 
                     // compute the block map, setup exception handlers and get the entrypoint(s)
-                    BciBlockMapping blockMap = BciBlockMapping.create(method, graphBuilderConfig.doLivenessAnalysis(), explodeLoops);
-                    loopHeaders = blockMap.getLoopHeaders();
-                    liveness = blockMap.liveness;
+                    BciBlockMapping newMapping = BciBlockMapping.create(stream, method);
+                    this.blockMap = newMapping;
+                    this.firstInstructionArray = new FixedWithNextNode[blockMap.getBlockCount()];
+                    this.entryStateArray = new HIRFrameStateBuilder[blockMap.getBlockCount()];
+
+                    if (graphBuilderConfig.doLivenessAnalysis()) {
+                        try (Scope s = Debug.scope("LivenessAnalysis")) {
+                            int maxLocals = method.getMaxLocals();
+                            liveness = LocalLiveness.compute(stream, blockMap.getBlocks(), maxLocals, blockMap.getLoopCount());
+                        } catch (Throwable e) {
+                            throw Debug.handle(e);
+                        }
+                    }
 
                     lastInstr = startInstruction;
                     this.setCurrentFrameState(startFrameState);
+                    stream.setBCI(0);
 
+                    BciBlock startBlock = blockMap.getStartBlock();
                     if (startInstruction == currentGraph.start()) {
                         StartNode startNode = currentGraph.start();
                         if (method.isSynchronized()) {
                             startNode.setStateAfter(frameState.create(BytecodeFrame.BEFORE_BCI));
                         } else {
-                            frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
+                            frameState.clearNonLiveLocals(startBlock, liveness, true);
                             assert bci() == 0;
                             startNode.setStateAfter(frameState.create(bci()));
                         }
@@ -270,7 +284,7 @@
                         // add a monitor enter to the start block
                         methodSynchronizedObject = synchronizedObject(frameState, method);
                         MonitorEnterNode monitorEnter = genMonitorEnter(methodSynchronizedObject);
-                        frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
+                        frameState.clearNonLiveLocals(startBlock, liveness, true);
                         assert bci() == 0;
                         monitorEnter.setStateAfter(frameState.create(bci()));
                     }
@@ -279,12 +293,12 @@
                         append(createInfoPointNode(InfopointReason.METHOD_START));
                     }
 
-                    currentBlock = blockMap.startBlock;
-                    blockMap.startBlock.setEntryState(0, frameState);
-                    if (blockMap.startBlock.isLoopHeader && !explodeLoops) {
-                        appendGoto(createTarget(blockMap.startBlock, frameState));
+                    currentBlock = blockMap.getStartBlock();
+                    setEntryState(startBlock, 0, frameState);
+                    if (startBlock.isLoopHeader && !explodeLoops) {
+                        appendGoto(startBlock);
                     } else {
-                        blockMap.startBlock.setFirstInstruction(0, lastInstr);
+                        setFirstInstruction(startBlock, 0, lastInstr);
                     }
 
                     int index = 0;
@@ -293,11 +307,10 @@
                         BciBlock block = blocks[index];
                         index = iterateBlock(blocks, block);
                     }
-                    processBlock(this, returnBlock);
-                    processBlock(this, unwindBlock);
 
-                    Debug.dump(currentGraph, "After bytecode parsing");
-
+                    if (Debug.isDumpEnabled() && this.beforeReturnNode != startInstruction) {
+                        Debug.dump(currentGraph, "Bytecodes parsed: " + method.getDeclaringClass().getUnqualifiedName() + "." + method.getName());
+                    }
                 }
             }
 
@@ -332,12 +345,10 @@
 
                     if (context.targetPeelIteration != -1) {
                         // We were reaching the backedge during explosion. Explode further.
-                        Debug.dump(currentGraph, "Before loop explosion " + context.targetPeelIteration);
                         context.peelIteration = context.targetPeelIteration;
                         context.targetPeelIteration = -1;
                     } else {
                         // We did not reach the backedge. Exit.
-                        Debug.dump(currentGraph, "after loop explosion " + context.peelIteration);
                         break;
                     }
                 }
@@ -345,27 +356,6 @@
                 return header.loopEnd + 1;
             }
 
-            private BciBlock returnBlock(int bci) {
-                if (returnBlock == null) {
-                    returnBlock = new BciBlock();
-                    returnBlock.startBci = bci;
-                    returnBlock.endBci = bci;
-                    returnBlock.setId(Integer.MAX_VALUE);
-                }
-                return returnBlock;
-            }
-
-            private BciBlock unwindBlock() {
-                if (unwindBlock == null) {
-                    unwindBlock = new ExceptionDispatchBlock();
-                    unwindBlock.startBci = -1;
-                    unwindBlock.endBci = -1;
-                    unwindBlock.deoptBci = method.isSynchronized() ? BytecodeFrame.UNWIND_BCI : BytecodeFrame.AFTER_EXCEPTION_BCI;
-                    unwindBlock.setId(Integer.MAX_VALUE);
-                }
-                return unwindBlock;
-            }
-
             /**
              * @param type the unresolved type of the constant
              */
@@ -472,7 +462,7 @@
 
             private DispatchBeginNode handleException(ValueNode exceptionObject, int bci) {
                 assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci";
-                Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, profilingInfo.getExceptionSeen(bci));
+                Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci)));
 
                 BciBlock dispatchBlock = currentBlock.exceptionDispatchBlock();
                 /*
@@ -481,7 +471,7 @@
                  * unwind immediately.
                  */
                 if (bci != currentBlock.endBci || dispatchBlock == null) {
-                    dispatchBlock = unwindBlock();
+                    dispatchBlock = blockMap.getUnwindBlock();
                 }
 
                 HIRFrameStateBuilder dispatchState = frameState.copy();
@@ -499,6 +489,7 @@
                     dispatchBegin.setStateAfter(dispatchState.create(bci));
                     dispatchState.setRethrowException(true);
                 }
+                this.controlFlowSplit = true;
                 FixedNode target = createTarget(dispatchBlock, dispatchState);
                 FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
                 finishedDispatch.setNext(target);
@@ -522,32 +513,32 @@
 
             @Override
             protected ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y) {
-                return new SubNode(x, y);
+                return SubNode.create(x, y);
             }
 
             @Override
             protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) {
-                return new MulNode(x, y);
+                return MulNode.create(x, y);
             }
 
             @Override
             protected ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new AddNode(x, y);
+                return AddNode.create(x, y);
             }
 
             @Override
             protected ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new SubNode(x, y);
+                return SubNode.create(x, y);
             }
 
             @Override
             protected ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new MulNode(x, y);
+                return MulNode.create(x, y);
             }
 
             @Override
             protected ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP) {
-                return new DivNode(x, y);
+                return DivNode.create(x, y);
             }
 
             @Override
@@ -587,62 +578,62 @@
 
             @Override
             protected ValueNode genAnd(Kind kind, ValueNode x, ValueNode y) {
-                return new AndNode(x, y);
+                return AndNode.create(x, y);
             }
 
             @Override
             protected ValueNode genOr(Kind kind, ValueNode x, ValueNode y) {
-                return new OrNode(x, y);
+                return OrNode.create(x, y);
             }
 
             @Override
             protected ValueNode genXor(Kind kind, ValueNode x, ValueNode y) {
-                return new XorNode(x, y);
+                return XorNode.create(x, y);
             }
 
             @Override
             protected ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-                return new NormalizeCompareNode(x, y, isUnorderedLess);
+                return NormalizeCompareNode.create(x, y, isUnorderedLess, constantReflection);
             }
 
             @Override
             protected ValueNode genFloatConvert(FloatConvert op, ValueNode input) {
-                return new FloatConvertNode(op, input);
+                return FloatConvertNode.create(op, input);
             }
 
             @Override
             protected ValueNode genNarrow(ValueNode input, int bitCount) {
-                return new NarrowNode(input, bitCount);
+                return NarrowNode.create(input, bitCount);
             }
 
             @Override
             protected ValueNode genSignExtend(ValueNode input, int bitCount) {
-                return new SignExtendNode(input, bitCount);
+                return SignExtendNode.create(input, bitCount);
             }
 
             @Override
             protected ValueNode genZeroExtend(ValueNode input, int bitCount) {
-                return new ZeroExtendNode(input, bitCount);
+                return ZeroExtendNode.create(input, bitCount);
             }
 
             @Override
             protected void genGoto() {
-                appendGoto(createTarget(currentBlock.getSuccessors().get(0), frameState));
+                appendGoto(currentBlock.getSuccessor(0));
                 assert currentBlock.numNormalSuccessors() == 1;
             }
 
             @Override
-            protected ValueNode genObjectEquals(ValueNode x, ValueNode y) {
+            protected LogicNode genObjectEquals(ValueNode x, ValueNode y) {
                 return ObjectEqualsNode.create(x, y, constantReflection);
             }
 
             @Override
-            protected ValueNode genIntegerEquals(ValueNode x, ValueNode y) {
+            protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) {
                 return IntegerEqualsNode.create(x, y, constantReflection);
             }
 
             @Override
-            protected ValueNode genIntegerLessThan(ValueNode x, ValueNode y) {
+            protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) {
                 return IntegerLessThanNode.create(x, y, constantReflection);
             }
 
@@ -664,12 +655,12 @@
 
             @Override
             protected ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck) {
-                return new CheckCastNode(type, object, profileForTypeCheck, forStoreCheck);
+                return CheckCastNode.create(type, object, profileForTypeCheck, forStoreCheck, currentGraph.getAssumptions());
             }
 
             @Override
             protected ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck) {
-                return new InstanceOfNode(type, object, profileForTypeCheck);
+                return InstanceOfNode.create(type, object, profileForTypeCheck);
             }
 
             @Override
@@ -832,7 +823,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;
@@ -852,22 +843,27 @@
                 }
                 if (invokeKind.hasReceiver()) {
                     emitExplicitExceptions(args[0], null);
-                    if (invokeKind.isIndirect() && this.optimisticOpts.useTypeCheckHints()) {
+                    if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) {
                         JavaTypeProfile profile = profilingInfo.getTypeProfile(bci());
                         args[0] = TypeProfileProxyNode.proxify(args[0], profile);
                     }
                 }
 
-                if (graphBuilderPlugins != null) {
-                    if (tryUsingInvocationPlugin(args, targetMethod, resultType)) {
-                        return;
+                if (tryInvocationPlugin(args, targetMethod, resultType)) {
+                    if (GraalOptions.TraceInlineDuringParsing.getValue()) {
+                        TTY.println(format("%sUsed invocation plugin for %s", nSpaces(currentDepth), targetMethod));
                     }
+                    return;
                 }
 
-                InlineInvokePlugin inlineInvokePlugin = graphBuilderConfig.getInlineInvokePlugin();
-                if (inlineInvokePlugin != null && invokeKind.isDirect() && targetMethod.canBeInlined() && targetMethod.hasBytecodes() &&
-                                inlineInvokePlugin.shouldInlineInvoke(targetMethod, currentDepth)) {
-                    parseAndInlineCallee(targetMethod, args);
+                if (tryAnnotatedInvocationPlugin(args, targetMethod)) {
+                    if (GraalOptions.TraceInlineDuringParsing.getValue()) {
+                        TTY.println(format("%sUsed annotated invocation plugin for %s", nSpaces(currentDepth), targetMethod));
+                    }
+                    return;
+                }
+
+                if (tryInline(args, targetMethod, invokeKind, returnType)) {
                     return;
                 }
 
@@ -875,7 +871,7 @@
 
                 // be conservative if information was not recorded (could result in endless
                 // recompiles otherwise)
-                if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
+                if (graphBuilderConfig.omitAllExceptionEdges() || (optimisticOpts.useExceptionProbability() && profilingInfo != null && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE)) {
                     createInvoke(callTarget, resultType);
                 } else {
                     InvokeWithExceptionNode invoke = createInvokeWithException(callTarget, resultType);
@@ -885,16 +881,17 @@
                 }
             }
 
-            private boolean tryUsingInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
-                InvocationPlugin plugin = graphBuilderPlugins.lookupInvocation(targetMethod);
+            private boolean tryInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
+                InvocationPlugin plugin = graphBuilderConfig.getInvocationPlugins().lookupInvocation(targetMethod);
                 if (plugin != null) {
                     int beforeStackSize = frameState.stackSize;
-                    boolean needsNullCheck = !targetMethod.isStatic() && !StampTool.isPointerNonNull(args[0].stamp());
+                    boolean needsNullCheck = !targetMethod.isStatic() && args[0].getKind() == Kind.Object && !StampTool.isPointerNonNull(args[0].stamp());
                     int nodeCount = currentGraph.getNodeCount();
                     Mark mark = needsNullCheck ? currentGraph.getMark() : null;
                     if (InvocationPlugin.execute(this, plugin, args)) {
-                        assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly";
-                        assert !needsNullCheck || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : "plugin needs to null check the receiver of " + targetMethod + ": " + args[0];
+                        assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : "plugin manipulated the stack incorrectly " + targetMethod;
+                        assert !needsNullCheck || args[0].usages().filter(isNotA(FrameState.class)).isEmpty() || containsNullCheckOf(currentGraph.getNewNodes(mark), args[0]) : "plugin needs to null check the receiver of " +
+                                        targetMethod + ": " + args[0];
                         return true;
                     }
                     assert nodeCount == currentGraph.getNodeCount() : "plugin that returns false must not create new nodes";
@@ -903,6 +900,11 @@
                 return false;
             }
 
+            private boolean tryAnnotatedInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod) {
+                AnnotatedInvocationPlugin plugin = graphBuilderConfig.getAnnotatedInvocationPlugin();
+                return plugin != null && plugin.apply(this, targetMethod, args);
+            }
+
             private boolean containsNullCheckOf(NodeIterable<Node> nodes, Node value) {
                 for (Node n : nodes) {
                     if (n instanceof GuardingPiNode) {
@@ -915,10 +917,36 @@
                 return false;
             }
 
-            private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args) {
-                BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, StructuredGraph.INVOCATION_ENTRY_BCI);
+            private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, JavaType returnType) {
+                InlineInvokePlugin plugin = graphBuilderConfig.getInlineInvokePlugin();
+                if (plugin == null || !invokeKind.isDirect() || !targetMethod.canBeInlined()) {
+                    return false;
+                }
+                ResolvedJavaMethod inlinedMethod = plugin.getInlinedMethod(this, targetMethod, args, returnType, currentDepth);
+                if (inlinedMethod != null && inlinedMethod.hasBytecodes()) {
+                    if (TraceInlineDuringParsing.getValue()) {
+                        int bci = this.bci();
+                        StackTraceElement ste = this.method.asStackTraceElement(bci);
+                        TTY.println(format("%s%s (%s:%d) inlining call to %s", nSpaces(currentDepth), method.getName(), ste.getFileName(), ste.getLineNumber(), inlinedMethod.format("%h.%n(%p)")));
+                    }
+                    parseAndInlineCallee(inlinedMethod, args, parsingReplacement || !inlinedMethod.equals(targetMethod));
+                    plugin.postInline(inlinedMethod);
+                    return true;
+                }
+
+                return false;
+            }
+
+            private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, boolean isReplacement) {
+                BytecodeParser parser = new BytecodeParser(metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, isReplacement);
                 final FrameState[] lazyFrameState = new FrameState[1];
-                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, () -> {
+
+                // Replacements often produce nodes with an illegal kind (e.g., pointer stamps)
+                // so the frame state builder should not check the types flowing through the frame
+                // since all such assertions are in terms of Java kinds.
+                boolean checkTypes = !isReplacement;
+
+                HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(targetMethod, currentGraph, checkTypes, () -> {
                     if (lazyFrameState[0] == null) {
                         lazyFrameState[0] = frameState.create(bci());
                     }
@@ -940,8 +968,22 @@
                 if (calleeBeforeUnwindNode != null) {
                     ValueNode calleeUnwindValue = parser.getUnwindValue();
                     assert calleeUnwindValue != null;
+                    if (calleeBeforeUnwindNode instanceof AbstractMergeNode) {
+                        AbstractMergeNode mergeNode = (AbstractMergeNode) calleeBeforeUnwindNode;
+                        HIRFrameStateBuilder dispatchState = frameState.copy();
+                        dispatchState.clearStack();
+                        dispatchState.apush(calleeUnwindValue);
+                        dispatchState.setRethrowException(true);
+                        mergeNode.setStateAfter(dispatchState.create(bci()));
+
+                    }
                     calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
                 }
+
+                // Record inlined method dependency in the graph
+                if (currentGraph.isInlinedMethodRecordingEnabled()) {
+                    currentGraph.getInlinedMethods().add(targetMethod);
+                }
             }
 
             protected MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, JavaType returnType) {
@@ -964,17 +1006,28 @@
 
             @Override
             protected void genReturn(ValueNode x) {
-                frameState.setRethrowException(false);
-                frameState.clearStack();
 
                 if (this.currentDepth == 0) {
+                    frameState.setRethrowException(false);
+                    frameState.clearStack();
                     beforeReturn(x);
                     append(new ReturnNode(x));
                 } else {
-                    if (x != null) {
-                        frameState.push(x.getKind(), x);
+                    if (blockMap.getReturnCount() == 1 || !controlFlowSplit) {
+                        // There is only a single return.
+                        beforeReturn(x);
+                        this.returnValue = x;
+                        this.beforeReturnNode = this.lastInstr;
+                        this.lastInstr = null;
+                    } else {
+                        frameState.setRethrowException(false);
+                        frameState.clearStack();
+                        if (x != null) {
+                            frameState.push(x.getKind(), x);
+                        }
+                        assert blockMap.getReturnCount() > 1;
+                        appendGoto(blockMap.getReturnBlock());
                     }
-                    appendGoto(createTarget(returnBlock(bci()), frameState));
                 }
             }
 
@@ -985,7 +1038,7 @@
 
                 synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x);
                 if (frameState.lockDepth() != 0) {
-                    throw new BailoutException("unbalanced monitors");
+                    throw bailout("unbalanced monitors");
                 }
             }
 
@@ -1002,7 +1055,7 @@
                 MonitorIdNode monitorId = frameState.peekMonitorId();
                 ValueNode lockedObject = frameState.popLock();
                 if (GraphUtil.originalValue(lockedObject) != GraphUtil.originalValue(x)) {
-                    throw new BailoutException("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject));
+                    throw bailout(String.format("unbalanced monitors: mismatch at monitorexit, %s != %s", GraphUtil.originalValue(x), GraphUtil.originalValue(lockedObject)));
                 }
                 MonitorExitNode monitorExit = append(new MonitorExitNode(x, monitorId, escapedReturnValue));
                 return monitorExit;
@@ -1022,7 +1075,7 @@
                 }
                 ConstantNode nextBciNode = getJsrConstant(nextBci);
                 frameState.push(Kind.Int, nextBciNode);
-                appendGoto(createTarget(successor, frameState));
+                appendGoto(successor);
             }
 
             @Override
@@ -1038,7 +1091,7 @@
                 if (!successor.getJsrScope().equals(scope.pop())) {
                     throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
                 }
-                appendGoto(createTarget(successor, frameState));
+                appendGoto(successor);
             }
 
             private ConstantNode getJsrConstant(long bci) {
@@ -1050,10 +1103,23 @@
 
             @Override
             protected void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
-                double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities);
-                IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors));
-                for (int i = 0; i < actualSuccessors.size(); i++) {
-                    switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState));
+                if (value.isConstant()) {
+                    JavaConstant constant = (JavaConstant) value.asConstant();
+                    int constantValue = constant.asInt();
+                    for (int i = 0; i < keys.length; ++i) {
+                        if (keys[i] == constantValue) {
+                            appendGoto(actualSuccessors.get(keySuccessors[i]));
+                            return;
+                        }
+                    }
+                    appendGoto(actualSuccessors.get(keySuccessors[keys.length]));
+                } else {
+                    this.controlFlowSplit = true;
+                    double[] successorProbabilities = successorProbabilites(actualSuccessors.size(), keySuccessors, keyProbabilities);
+                    IntegerSwitchNode switchNode = append(new IntegerSwitchNode(value, actualSuccessors.size(), keys, keyProbabilities, keySuccessors));
+                    for (int i = 0; i < actualSuccessors.size(); i++) {
+                        switchNode.setBlockSuccessor(i, createBlockTarget(successorProbabilities[i], actualSuccessors.get(i), frameState));
+                    }
                 }
             }
 
@@ -1063,8 +1129,13 @@
                 return ConstantNode.forConstant(constant, metaAccess, currentGraph);
             }
 
+            @SuppressWarnings("unchecked")
             @Override
-            protected ValueNode append(ValueNode v) {
+            public ValueNode append(ValueNode v) {
+                if (v.graph() != null) {
+                    // This node was already appended to the graph.
+                    return v;
+                }
                 if (v instanceof ControlSinkNode) {
                     return append((ControlSinkNode) v);
                 }
@@ -1108,6 +1179,9 @@
             }
 
             public <T extends FloatingNode> T append(T v) {
+                if (v.graph() != null) {
+                    return v;
+                }
                 T added = currentGraph.unique(v);
                 return added;
             }
@@ -1124,7 +1198,7 @@
                         do {
                             long lMask = 1L << pos;
                             if ((exits & lMask) != 0) {
-                                exitLoops.add(loopHeaders[pos]);
+                                exitLoops.add(blockMap.getLoopHeader(pos));
                                 exits &= ~lMask;
                             }
                             pos++;
@@ -1144,7 +1218,7 @@
                         }
                         HIRFrameStateBuilder newState = state.copy();
                         for (BciBlock loop : exitLoops) {
-                            LoopBeginNode loopBegin = (LoopBeginNode) loop.getFirstInstruction(this.getCurrentDimension());
+                            LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(loop, this.getCurrentDimension());
                             LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin));
                             if (lastLoopExit != null) {
                                 lastLoopExit.setNext(loopExit);
@@ -1153,8 +1227,8 @@
                                 firstLoopExit = loopExit;
                             }
                             lastLoopExit = loopExit;
-                            Debug.log("Target %s (%s) Exits %s, scanning framestates...", targetBlock, target, loop);
-                            newState.insertLoopProxies(loopExit, (HIRFrameStateBuilder) loop.getEntryState(this.getCurrentDimension()));
+                            Debug.log("Target %s Exits %s, scanning framestates...", targetBlock, loop);
+                            newState.insertLoopProxies(loopExit, (HIRFrameStateBuilder) getEntryState(loop, this.getCurrentDimension()));
                             loopExit.setStateAfter(newState.create(bci));
                         }
 
@@ -1165,6 +1239,98 @@
                 return new Target(target, state);
             }
 
+            private AbstractFrameStateBuilder<?, ?> getEntryState(BciBlock block, int dimension) {
+                int id = block.id;
+                if (dimension == 0) {
+                    return entryStateArray[id];
+                } else {
+                    return getEntryStateMultiDimension(dimension, id);
+                }
+            }
+
+            private AbstractFrameStateBuilder<?, ?> getEntryStateMultiDimension(int dimension, int id) {
+                if (entryStateMatrix != null && dimension - 1 < entryStateMatrix.length) {
+                    AbstractFrameStateBuilder<?, ?>[] entryStateArrayEntry = entryStateMatrix[dimension - 1];
+                    if (entryStateArrayEntry == null) {
+                        return null;
+                    }
+                    return entryStateArrayEntry[id];
+                } else {
+                    return null;
+                }
+            }
+
+            private void setEntryState(BciBlock block, int dimension, HIRFrameStateBuilder entryState) {
+                int id = block.id;
+                if (dimension == 0) {
+                    this.entryStateArray[id] = entryState;
+                } else {
+                    setEntryStateMultiDimension(dimension, entryState, id);
+                }
+            }
+
+            private void setEntryStateMultiDimension(int dimension, HIRFrameStateBuilder entryState, int id) {
+                if (entryStateMatrix == null) {
+                    entryStateMatrix = new HIRFrameStateBuilder[4][];
+                }
+                if (dimension - 1 < entryStateMatrix.length) {
+                    // We are within bounds.
+                } else {
+                    // We are out of bounds.
+                    entryStateMatrix = Arrays.copyOf(entryStateMatrix, Math.max(entryStateMatrix.length * 2, dimension));
+                }
+                if (entryStateMatrix[dimension - 1] == null) {
+                    entryStateMatrix[dimension - 1] = new HIRFrameStateBuilder[blockMap.getBlockCount()];
+                }
+                entryStateMatrix[dimension - 1][id] = entryState;
+            }
+
+            private void setFirstInstruction(BciBlock block, int dimension, FixedWithNextNode firstInstruction) {
+                int id = block.id;
+                if (dimension == 0) {
+                    this.firstInstructionArray[id] = firstInstruction;
+                } else {
+                    setFirstInstructionMultiDimension(dimension, firstInstruction, id);
+                }
+            }
+
+            private void setFirstInstructionMultiDimension(int dimension, FixedWithNextNode firstInstruction, int id) {
+                if (firstInstructionMatrix == null) {
+                    firstInstructionMatrix = new FixedWithNextNode[4][];
+                }
+                if (dimension - 1 < firstInstructionMatrix.length) {
+                    // We are within bounds.
+                } else {
+                    // We are out of bounds.
+                    firstInstructionMatrix = Arrays.copyOf(firstInstructionMatrix, Math.max(firstInstructionMatrix.length * 2, dimension));
+                }
+                if (firstInstructionMatrix[dimension - 1] == null) {
+                    firstInstructionMatrix[dimension - 1] = new FixedWithNextNode[blockMap.getBlockCount()];
+                }
+                firstInstructionMatrix[dimension - 1][id] = firstInstruction;
+            }
+
+            private FixedWithNextNode getFirstInstruction(BciBlock block, int dimension) {
+                int id = block.id;
+                if (dimension == 0) {
+                    return firstInstructionArray[id];
+                } else {
+                    return getFirstInstructionMultiDimension(dimension, id);
+                }
+            }
+
+            private FixedWithNextNode getFirstInstructionMultiDimension(int dimension, int id) {
+                if (firstInstructionMatrix != null && dimension - 1 < firstInstructionMatrix.length) {
+                    FixedWithNextNode[] firstInstructionArrayEntry = firstInstructionMatrix[dimension - 1];
+                    if (firstInstructionArrayEntry == null) {
+                        return null;
+                    }
+                    return firstInstructionArrayEntry[id];
+                } else {
+                    return null;
+                }
+            }
+
             private FixedNode createTarget(double probability, BciBlock block, HIRFrameStateBuilder stateAfter) {
                 assert probability >= 0 && probability <= 1.01 : probability;
                 if (isNeverExecutedCode(probability)) {
@@ -1176,94 +1342,71 @@
             }
 
             private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) {
+                return createTarget(block, state, false);
+            }
+
+            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean isGoto) {
                 assert block != null && state != null;
                 assert !block.isExceptionEntry || state.stackSize() == 1;
 
-                int operatingDimension = this.getCurrentDimension();
-                if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) {
-                    int i;
-                    for (i = explodeLoopsContext.size() - 1; i >= 0; --i) {
-                        ExplodedLoopContext context = explodeLoopsContext.elementAt(i);
-                        if (context.header == block) {
-
-                            // We have a hit on our current explosion context loop begin.
-                            if (context.targetPeelIteration == -1) {
-                                // This is the first hit => allocate a new dimension and at the same
-                                // time mark the context loop begin as hit during the current
-                                // iteration.
-                                context.targetPeelIteration = nextPeelIteration++;
-                                if (nextPeelIteration > GraalOptions.MaximumLoopExplosionCount.getValue()) {
-                                    throw new BailoutException("too many loop explosion interations - does the explosion not terminate?");
-                                }
-                            }
+                int operatingDimension = findOperatingDimension(block);
 
-                            // Operate on the target dimension.
-                            operatingDimension = context.targetPeelIteration;
-                            break;
-                        } else if (block.getId() > context.header.getId() && block.getId() <= context.header.loopEnd) {
-                            // We hit the range of this context.
-                            operatingDimension = context.peelIteration;
-                            break;
-                        }
-                    }
-
-                    if (i == -1) {
-                        // I did not find a dimension.
-                        operatingDimension = 0;
-                    }
-                }
-
-                if (block.getFirstInstruction(operatingDimension) == null) {
+                if (getFirstInstruction(block, operatingDimension) == null) {
                     /*
                      * This is the first time we see this block as a branch target. Create and
                      * return a placeholder that later can be replaced with a MergeNode when we see
                      * this block again.
                      */
                     FixedNode targetNode;
-                    block.setFirstInstruction(operatingDimension, currentGraph.add(new BeginNode()));
-                    targetNode = block.getFirstInstruction(operatingDimension);
+                    if (isGoto && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
+                        setFirstInstruction(block, operatingDimension, lastInstr);
+                        lastInstr = null;
+                    } else {
+                        setFirstInstruction(block, operatingDimension, currentGraph.add(new BeginNode()));
+                    }
+                    targetNode = getFirstInstruction(block, operatingDimension);
                     Target target = checkLoopExit(targetNode, block, state);
                     FixedNode result = target.fixed;
-                    AbstractFrameStateBuilder<?, ?> entryState = target.state == state ? state.copy() : target.state;
-                    block.setEntryState(operatingDimension, entryState);
-                    entryState.clearNonLiveLocals(block, liveness, true);
+                    HIRFrameStateBuilder currentEntryState = target.state == state ? state.copy() : target.state;
+                    setEntryState(block, operatingDimension, currentEntryState);
+                    currentEntryState.clearNonLiveLocals(block, liveness, true);
 
                     Debug.log("createTarget %s: first visit, result: %s", block, targetNode);
                     return result;
                 }
 
                 // We already saw this block before, so we have to merge states.
-                if (!((HIRFrameStateBuilder) block.getEntryState(operatingDimension)).isCompatibleWith(state)) {
-                    throw new BailoutException("stacks do not match; bytecodes would not verify");
+                if (!((HIRFrameStateBuilder) getEntryState(block, operatingDimension)).isCompatibleWith(state)) {
+                    throw bailout("stacks do not match; bytecodes would not verify");
                 }
 
-                if (block.getFirstInstruction(operatingDimension) instanceof LoopBeginNode) {
+                if (getFirstInstruction(block, operatingDimension) instanceof LoopBeginNode) {
                     assert this.explodeLoops || (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
                     /*
                      * Backward loop edge. We need to create a special LoopEndNode and merge with
                      * the loop begin node created before.
                      */
-                    LoopBeginNode loopBegin = (LoopBeginNode) block.getFirstInstruction(operatingDimension);
+                    LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block, operatingDimension);
                     Target target = checkLoopExit(currentGraph.add(new LoopEndNode(loopBegin)), block, state);
                     FixedNode result = target.fixed;
-                    ((HIRFrameStateBuilder) block.getEntryState(operatingDimension)).merge(loopBegin, target.state);
+                    ((HIRFrameStateBuilder) getEntryState(block, operatingDimension)).merge(loopBegin, target.state);
 
                     Debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
                     return result;
                 }
                 assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
-                assert block.getFirstInstruction(operatingDimension).next() == null : "bytecodes already parsed for block";
+                assert getFirstInstruction(block, operatingDimension).next() == null : "bytecodes already parsed for block";
 
-                if (block.getFirstInstruction(operatingDimension) instanceof AbstractBeginNode && !(block.getFirstInstruction(operatingDimension) instanceof AbstractMergeNode)) {
+                if (getFirstInstruction(block, operatingDimension) instanceof AbstractBeginNode && !(getFirstInstruction(block, operatingDimension) instanceof AbstractMergeNode)) {
                     /*
                      * This is the second time we see this block. Create the actual MergeNode and
                      * the End Node for the already existing edge. For simplicity, we leave the
                      * placeholder in the graph and just append the new nodes after the placeholder.
                      */
-                    AbstractBeginNode placeholder = (AbstractBeginNode) block.getFirstInstruction(operatingDimension);
+                    AbstractBeginNode placeholder = (AbstractBeginNode) getFirstInstruction(block, operatingDimension);
 
                     // The EndNode for the already existing edge.
-                    AbstractEndNode end = currentGraph.add(new EndNode());
+                    EndNode end = currentGraph.add(new EndNode());
                     // The MergeNode that replaces the placeholder.
                     AbstractMergeNode mergeNode = currentGraph.add(new MergeNode());
                     FixedNode next = placeholder.next();
@@ -1278,22 +1421,63 @@
                     mergeNode.addForwardEnd(end);
                     mergeNode.setNext(next);
 
-                    block.setFirstInstruction(operatingDimension, mergeNode);
+                    setFirstInstruction(block, operatingDimension, mergeNode);
                 }
 
-                AbstractMergeNode mergeNode = (AbstractMergeNode) block.getFirstInstruction(operatingDimension);
+                AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block, operatingDimension);
 
                 // The EndNode for the newly merged edge.
-                AbstractEndNode newEnd = currentGraph.add(new EndNode());
+                EndNode newEnd = currentGraph.add(new EndNode());
                 Target target = checkLoopExit(newEnd, block, state);
                 FixedNode result = target.fixed;
-                ((HIRFrameStateBuilder) block.getEntryState(operatingDimension)).merge(mergeNode, target.state);
+                ((HIRFrameStateBuilder) getEntryState(block, operatingDimension)).merge(mergeNode, target.state);
                 mergeNode.addForwardEnd(newEnd);
 
                 Debug.log("createTarget %s: merging state, result: %s", block, result);
                 return result;
             }
 
+            private int findOperatingDimension(BciBlock block) {
+                if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) {
+                    return findOperatingDimensionWithLoopExplosion(block);
+                }
+                return this.getCurrentDimension();
+            }
+
+            private int findOperatingDimensionWithLoopExplosion(BciBlock block) {
+                int i;
+                for (i = explodeLoopsContext.size() - 1; i >= 0; --i) {
+                    ExplodedLoopContext context = explodeLoopsContext.elementAt(i);
+                    if (context.header == block) {
+
+                        // We have a hit on our current explosion context loop begin.
+                        if (context.targetPeelIteration == -1) {
+                            // This is the first hit => allocate a new dimension and at the same
+                            // time mark the context loop begin as hit during the current
+                            // iteration.
+                            context.targetPeelIteration = nextPeelIteration++;
+                            if (nextPeelIteration > MaximumLoopExplosionCount.getValue()) {
+                                String message = "too many loop explosion interations - does the explosion not terminate for method " + method + "?";
+                                if (FailedLoopExplosionIsFatal.getValue()) {
+                                    throw new RuntimeException(message);
+                                } else {
+                                    throw bailout(message);
+                                }
+                            }
+                        }
+
+                        // Operate on the target dimension.
+                        return context.targetPeelIteration;
+                    } else if (block.getId() > context.header.getId() && block.getId() <= context.header.loopEnd) {
+                        // We hit the range of this context.
+                        return context.peelIteration;
+                    }
+                }
+
+                // No dimension found.
+                return 0;
+            }
+
             /**
              * Returns a block begin node with the specified state. If the specified probability is
              * 0, the block deoptimizes immediately.
@@ -1317,33 +1501,37 @@
 
             protected void processBlock(BytecodeParser parser, BciBlock block) {
                 // Ignore blocks that have no predecessors by the time their bytecodes are parsed
-                if (block == null || block.getFirstInstruction(this.getCurrentDimension()) == null) {
+                if (block == null || getFirstInstruction(block, this.getCurrentDimension()) == null) {
                     Debug.log("Ignoring block %s", block);
                     return;
                 }
-                try (Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, block.getFirstInstruction(this.getCurrentDimension()), block.isLoopHeader)) {
+                try (Indent indent = Debug.logAndIndent("Parsing block %s  firstInstruction: %s  loopHeader: %b", block, getFirstInstruction(block, this.getCurrentDimension()), block.isLoopHeader)) {
 
-                    lastInstr = block.getFirstInstruction(this.getCurrentDimension());
-                    frameState = (HIRFrameStateBuilder) block.getEntryState(this.getCurrentDimension());
+                    lastInstr = getFirstInstruction(block, this.getCurrentDimension());
+                    frameState = (HIRFrameStateBuilder) getEntryState(block, this.getCurrentDimension());
                     parser.setCurrentFrameState(frameState);
                     currentBlock = block;
 
                     if (lastInstr instanceof AbstractMergeNode) {
-                        int bci = block.startBci;
-                        if (block instanceof ExceptionDispatchBlock) {
-                            bci = ((ExceptionDispatchBlock) block).deoptBci;
+
+                        AbstractMergeNode abstractMergeNode = (AbstractMergeNode) lastInstr;
+                        if (abstractMergeNode.stateAfter() == null) {
+                            int bci = block.startBci;
+                            if (block instanceof ExceptionDispatchBlock) {
+                                bci = ((ExceptionDispatchBlock) block).deoptBci;
+                            }
+                            abstractMergeNode.setStateAfter(frameState.create(bci));
                         }
-                        ((AbstractMergeNode) lastInstr).setStateAfter(frameState.create(bci));
                     }
 
-                    if (block == returnBlock) {
+                    if (block == blockMap.getReturnBlock()) {
                         Kind returnKind = method.getSignature().getReturnKind().getStackKind();
                         ValueNode x = returnKind == Kind.Void ? null : frameState.pop(returnKind);
                         assert frameState.stackSize() == 0;
                         beforeReturn(x);
                         this.returnValue = x;
                         this.beforeReturnNode = this.lastInstr;
-                    } else if (block == unwindBlock) {
+                    } else if (block == blockMap.getUnwindBlock()) {
                         if (currentDepth == 0) {
                             frameState.setRethrowException(false);
                             createUnwind();
@@ -1375,7 +1563,7 @@
              * </pre>
              */
             private void connectLoopEndToBegin() {
-                for (LoopBeginNode begin : currentGraph.getNodes(LoopBeginNode.class)) {
+                for (LoopBeginNode begin : currentGraph.getNodes(LoopBeginNode.TYPE)) {
                     if (begin.loopEnds().isEmpty()) {
                         assert begin.forwardEndCount() == 1;
                         currentGraph.reduceDegenerateLoopBegin(begin);
@@ -1407,7 +1595,7 @@
                 assert frameState.stackSize() == 1 : frameState;
                 if (block.handler.isCatchAll()) {
                     assert block.getSuccessorCount() == 1;
-                    appendGoto(createTarget(block.getSuccessor(0), frameState));
+                    appendGoto(block.getSuccessor(0));
                     return;
                 }
 
@@ -1420,7 +1608,7 @@
                     ResolvedJavaType resolvedCatchType = (ResolvedJavaType) catchType;
                     for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
                         if (skippedType.isAssignableFrom(resolvedCatchType)) {
-                            BciBlock nextBlock = block.getSuccessorCount() == 1 ? unwindBlock() : block.getSuccessor(1);
+                            BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
                             ValueNode exception = frameState.stackAt(0);
                             FixedNode trueSuccessor = currentGraph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
                             FixedNode nextDispatch = createTarget(nextBlock, frameState);
@@ -1431,7 +1619,7 @@
                 }
 
                 if (initialized) {
-                    BciBlock nextBlock = block.getSuccessorCount() == 1 ? unwindBlock() : block.getSuccessor(1);
+                    BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
                     ValueNode exception = frameState.stackAt(0);
                     CheckCastNode checkCast = currentGraph.add(new CheckCastNode((ResolvedJavaType) catchType, exception, null, false));
                     frameState.apop();
@@ -1447,9 +1635,10 @@
                 }
             }
 
-            private void appendGoto(FixedNode target) {
-                if (lastInstr != null) {
-                    lastInstr.setNext(target);
+            private void appendGoto(BciBlock successor) {
+                FixedNode targetInstr = createTarget(successor, frameState, true);
+                if (lastInstr != null && lastInstr != targetInstr) {
+                    lastInstr.setNext(targetInstr);
                 }
             }
 
@@ -1462,7 +1651,8 @@
                 if (block.isLoopHeader && !explodeLoops) {
                     // Create the loop header block, which later will merge the backward branches of
                     // the loop.
-                    AbstractEndNode preLoopEnd = currentGraph.add(new EndNode());
+                    controlFlowSplit = true;
+                    EndNode preLoopEnd = currentGraph.add(new EndNode());
                     LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode());
                     lastInstr.setNext(preLoopEnd);
                     // Add the single non-loop predecessor of the loop header.
@@ -1478,12 +1668,12 @@
                      * merge to the loop header. This ensures that the loop header has exactly one
                      * non-loop predecessor.
                      */
-                    block.setFirstInstruction(this.getCurrentDimension(), loopBegin);
+                    setFirstInstruction(block, this.getCurrentDimension(), loopBegin);
                     /*
                      * We need to preserve the frame state builder of the loop header so that we can
                      * merge values for phi functions, so make a copy of it.
                      */
-                    block.setEntryState(this.getCurrentDimension(), frameState.copy());
+                    setEntryState(block, this.getCurrentDimension(), frameState.copy());
 
                     Debug.log("  created loop header %s", loopBegin);
                 }
@@ -1509,8 +1699,8 @@
 
                     // read the opcode
                     int opcode = stream.currentBC();
-                    traceState();
-                    traceInstruction(bci, opcode, bci == block.startBci);
+                    assert traceState();
+                    assert traceInstruction(bci, opcode, bci == block.startBci);
                     if (currentDepth == 0 && bci == entryBCI) {
                         if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
                             throw new BailoutException("OSR into a JSR scope is not supported");
@@ -1547,7 +1737,7 @@
                             assert !block.getSuccessor(0).isExceptionEntry;
                             assert block.numNormalSuccessors() == 1;
                             // we fell through to the next block, add a goto and break
-                            appendGoto(createTarget(block.getSuccessor(0), frameState));
+                            appendGoto(block.getSuccessor(0));
                             break;
                         }
                     }
@@ -1573,10 +1763,11 @@
                 }
             }
 
-            private void traceState() {
+            private boolean traceState() {
                 if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_STATE && Debug.isLogEnabled()) {
                     traceStateHelper();
                 }
+                return true;
             }
 
             private void traceStateHelper() {
@@ -1593,18 +1784,14 @@
 
             @Override
             protected void genIf(ValueNode x, Condition cond, ValueNode y) {
-                // assert !x.isDeleted() && !y.isDeleted();
-                // assert currentBlock.numNormalSuccessors() == 2;
-                assert currentBlock.getSuccessors().size() == 2;
-                BciBlock trueBlock = currentBlock.getSuccessors().get(0);
-                BciBlock falseBlock = currentBlock.getSuccessors().get(1);
+                assert currentBlock.getSuccessorCount() == 2;
+                BciBlock trueBlock = currentBlock.getSuccessor(0);
+                BciBlock falseBlock = currentBlock.getSuccessor(1);
                 if (trueBlock == falseBlock) {
-                    appendGoto(createTarget(trueBlock, frameState));
+                    appendGoto(trueBlock);
                     return;
                 }
 
-                double probability = branchProbability();
-
                 // the mirroring and negation operations get the condition into canonical form
                 boolean mirror = cond.canonicalMirror();
                 boolean negate = cond.canonicalNegate();
@@ -1612,7 +1799,7 @@
                 ValueNode a = mirror ? y : x;
                 ValueNode b = mirror ? x : y;
 
-                ValueNode condition;
+                LogicNode condition;
                 assert !a.getKind().isNumericFloat();
                 if (cond == Condition.EQ || cond == Condition.NE) {
                     if (a.getKind() == Kind.Object) {
@@ -1624,7 +1811,12 @@
                     assert a.getKind() != Kind.Object && !cond.isUnsigned();
                     condition = genIntegerLessThan(a, b);
                 }
-                condition = genUnique(condition);
+
+                if (condition instanceof LogicNegationNode) {
+                    LogicNegationNode logicNegationNode = (LogicNegationNode) condition;
+                    negate = !negate;
+                    condition = logicNegationNode.getValue();
+                }
 
                 if (condition instanceof LogicConstantNode) {
                     LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
@@ -1636,8 +1828,57 @@
                     if (value) {
                         nextBlock = trueBlock;
                     }
-                    appendGoto(createTarget(nextBlock, frameState));
+                    appendGoto(nextBlock);
                 } else {
+
+                    if (condition.graph() == null) {
+                        condition = currentGraph.unique(condition);
+                    }
+
+                    // Need to get probability based on current bci.
+                    double probability = branchProbability();
+
+                    int oldBci = stream.currentBCI();
+                    int trueBlockInt = checkPositiveIntConstantPushed(trueBlock);
+                    if (trueBlockInt != -1) {
+                        int falseBlockInt = checkPositiveIntConstantPushed(falseBlock);
+                        if (falseBlockInt != -1) {
+
+                            boolean genReturn = false;
+                            boolean genConditional = false;
+                            if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) {
+                                genConditional = true;
+                            } else if (this.currentDepth != 0 && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
+                                genReturn = true;
+                                genConditional = true;
+                            }
+
+                            if (genConditional) {
+                                ConstantNode trueValue = currentGraph.unique(ConstantNode.forInt(trueBlockInt));
+                                ConstantNode falseValue = currentGraph.unique(ConstantNode.forInt(falseBlockInt));
+                                if (negate) {
+                                    ConstantNode tmp = falseValue;
+                                    falseValue = trueValue;
+                                    trueValue = tmp;
+                                }
+                                ValueNode conditionalNode = ConditionalNode.create(condition, trueValue, falseValue);
+                                if (conditionalNode.graph() == null) {
+                                    conditionalNode = currentGraph.addOrUnique(conditionalNode);
+                                }
+                                if (genReturn) {
+                                    this.genReturn(conditionalNode);
+                                } else {
+                                    frameState.push(Kind.Int, conditionalNode);
+                                    appendGoto(trueBlock.getSuccessor(0));
+                                    stream.setBCI(oldBci);
+                                }
+                                return;
+                            }
+                        }
+                    }
+
+                    this.controlFlowSplit = true;
+
                     ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
                     ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
@@ -1646,6 +1887,32 @@
                 }
             }
 
+            private int checkPositiveIntConstantPushed(BciBlock block) {
+                stream.setBCI(block.startBci);
+                int currentBC = stream.currentBC();
+                if (currentBC >= Bytecodes.ICONST_0 && currentBC <= Bytecodes.ICONST_5) {
+                    int constValue = currentBC - Bytecodes.ICONST_0;
+                    return constValue;
+                }
+                return -1;
+            }
+
+            private boolean gotoOrFallThroughAfterConstant(BciBlock block) {
+                stream.setBCI(block.startBci);
+                int currentBCI = stream.nextBCI();
+                stream.setBCI(currentBCI);
+                int currentBC = stream.currentBC();
+                return stream.currentBCI() > block.endBci || currentBC == Bytecodes.GOTO || currentBC == Bytecodes.GOTO_W;
+            }
+
+            private boolean returnAfterConstant(BciBlock block) {
+                stream.setBCI(block.startBci);
+                int currentBCI = stream.nextBCI();
+                stream.setBCI(currentBCI);
+                int currentBC = stream.currentBC();
+                return currentBC == Bytecodes.IRETURN;
+            }
+
             public StampProvider getStampProvider() {
                 return stampProvider;
             }
@@ -1655,7 +1922,7 @@
             }
 
             public Assumptions getAssumptions() {
-                return assumptions;
+                return currentGraph.getAssumptions();
             }
 
             public void push(Kind kind, ValueNode value) {
@@ -1675,6 +1942,37 @@
                 return constantReflection;
             }
 
+            public SnippetReflectionProvider getSnippetReflection() {
+                return snippetReflectionProvider;
+            }
+
+            public boolean parsingReplacement() {
+                return parsingReplacement;
+            }
+
+            public StructuredGraph getGraph() {
+                return currentGraph;
+            }
+
+            public GuardingNode getCurrentBlockGuard() {
+                return (GuardingNode) getFirstInstruction(currentBlock, getCurrentDimension());
+            }
+
+            @Override
+            public String toString() {
+                return method.format("%H.%n(%p)@") + bci();
+            }
+
+            public BailoutException bailout(String string) {
+                FrameState currentFrameState = this.frameState.create(bci());
+                StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState);
+                BailoutException bailout = new BailoutException(string);
+                throw GraphUtil.createBailoutException(string, bailout, elements);
+            }
         }
     }
+
+    static String nSpaces(int n) {
+        return n == 0 ? "" : format("%" + n + "s", "");
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,14 +22,141 @@
  */
 package com.oracle.graal.java;
 
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+
 /**
  * Marker interface for graph builder plugins.
- *
- * Concrete plugins implement one of the sub-interfaces of this interface.
- *
- * @see GraphBuilderPluginsProvider
- * @see GraphBuilderPlugins
- * @see GraphBuilderPlugins.Registration
  */
 public interface GraphBuilderPlugin {
+
+    public interface LoadFieldPlugin extends GraphBuilderPlugin {
+        @SuppressWarnings("unused")
+        default boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
+            return false;
+        }
+
+        @SuppressWarnings("unused")
+        default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) {
+            return false;
+        }
+
+        default boolean tryConstantFold(GraphBuilderContext builder, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ResolvedJavaField field, JavaConstant asJavaConstant) {
+            JavaConstant result = constantReflection.readConstantFieldValue(field, asJavaConstant);
+            if (result != null) {
+                ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, metaAccess));
+                builder.push(constantNode.getKind().getStackKind(), constantNode);
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Plugin for customizing how the graph builder handles a CHECKCAST instruction in the context
+     * of the instruction that consumes it from the stack.
+     */
+    public interface CheckCastPlugin extends GraphBuilderPlugin {
+        boolean apply(GraphBuilderContext builder, ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck);
+    }
+
+    public interface InlineInvokePlugin extends GraphBuilderPlugin {
+
+        default void postInline(@SuppressWarnings("unused") ResolvedJavaMethod inlinedTargetMethod) {
+
+        }
+
+        ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType, int depth);
+    }
+
+    public interface LoopExplosionPlugin extends GraphBuilderPlugin {
+        boolean shouldExplodeLoops(ResolvedJavaMethod method);
+    }
+
+    public interface ParameterPlugin extends GraphBuilderPlugin {
+        FloatingNode interceptParameter(int index);
+    }
+
+    /**
+     * Plugin for handling an invocation based on the annotations of the invoked method.
+     */
+    public interface AnnotatedInvocationPlugin extends GraphBuilderPlugin {
+        /**
+         * Executes this plugin for an invocation of a given method with a given set of arguments.
+         *
+         * @return {@code true} if this plugin handled the invocation, {@code false} if not
+         */
+        boolean apply(GraphBuilderContext builder, ResolvedJavaMethod method, ValueNode[] args);
+    }
+
+    /**
+     * Plugin for handling a specific method invocation.
+     */
+    public interface InvocationPlugin extends GraphBuilderPlugin {
+        /**
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         */
+        default boolean apply(GraphBuilderContext builder) {
+            throw invalidHandler(builder);
+        }
+
+        /**
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg) {
+            throw invalidHandler(builder, arg);
+        }
+
+        /**
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
+            throw invalidHandler(builder, arg1, arg2);
+        }
+
+        /**
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+            throw invalidHandler(builder, arg1, arg2, arg3);
+        }
+
+        /**
+         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
+         */
+        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+            throw invalidHandler(builder, arg1, arg2, arg3, arg4);
+        }
+
+        /**
+         * Executes a given plugin against a set of invocation arguments by dispatching to the
+         * plugin's {@code apply(...)} method that matches the number of arguments.
+         *
+         * @return {@code true} if the plugin handled the invocation, {@code false} if the graph
+         *         builder should process the invoke further (e.g., by inlining it or creating an
+         *         {@link Invoke} node). A plugin that does not handle an invocation must not modify
+         *         the graph being constructed.
+         */
+        static boolean execute(GraphBuilderContext builder, InvocationPlugin plugin, ValueNode[] args) {
+            if (args.length == 0) {
+                return plugin.apply(builder);
+            } else if (args.length == 1) {
+                return plugin.apply(builder, args[0]);
+            } else if (args.length == 2) {
+                return plugin.apply(builder, args[0], args[1]);
+            } else if (args.length == 3) {
+                return plugin.apply(builder, args[0], args[1], args[2]);
+            } else if (args.length == 4) {
+                return plugin.apply(builder, args[0], args[1], args[2], args[3]);
+            } else {
+                throw plugin.invalidHandler(builder, args);
+            }
+        }
+
+        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) {
+            return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length);
+        }
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugins.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +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 java.lang.String.*;
-
-import java.lang.reflect.*;
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-
-/**
- * Interface for managing a set of graph builder {@link GraphBuilderPlugin}s.
- */
-public interface GraphBuilderPlugins {
-
-    public interface LoadFieldPlugin extends GraphBuilderPlugin {
-        @SuppressWarnings("unused")
-        default boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
-            return false;
-        }
-
-        @SuppressWarnings("unused")
-        default boolean apply(GraphBuilderContext graphBuilderContext, ResolvedJavaField staticField) {
-            return false;
-        }
-    }
-
-    public interface ParameterPlugin extends GraphBuilderPlugin {
-        FloatingNode interceptParameter(int index);
-    }
-
-    public interface InlineInvokePlugin extends GraphBuilderPlugin {
-        boolean shouldInlineInvoke(ResolvedJavaMethod method, int depth);
-    }
-
-    public interface LoopExplosionPlugin extends GraphBuilderPlugin {
-        boolean shouldExplodeLoops(ResolvedJavaMethod method);
-    }
-
-    /**
-     * Plugin for handling a method invocation.
-     */
-    public interface InvocationPlugin extends GraphBuilderPlugin {
-        /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
-         */
-        default boolean apply(GraphBuilderContext builder) {
-            throw invalidHandler(builder);
-        }
-
-        /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
-         */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg) {
-            throw invalidHandler(builder, arg);
-        }
-
-        /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
-         */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
-            throw invalidHandler(builder, arg1, arg2);
-        }
-
-        /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
-         */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-            throw invalidHandler(builder, arg1, arg2, arg3);
-        }
-
-        /**
-         * @see #execute(GraphBuilderContext, InvocationPlugin, ValueNode[])
-         */
-        default boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
-            throw invalidHandler(builder, arg1, arg2, arg3, arg4);
-        }
-
-        /**
-         * Executes a given plugin against a set of invocation arguments by dispatching to the
-         * plugin's {@code apply(...)} method that matches the number of arguments.
-         *
-         * @return {@code true} if the plugin handled the invocation, {@code false} if the graph
-         *         builder should process the invoke further (e.g., by inlining it or creating an
-         *         {@link Invoke} node). A plugin that does not handle an invocation must not modify
-         *         the graph being constructed.
-         */
-        static boolean execute(GraphBuilderContext builder, InvocationPlugin plugin, ValueNode[] args) {
-            if (args.length == 0) {
-                return plugin.apply(builder);
-            } else if (args.length == 1) {
-                return plugin.apply(builder, args[0]);
-            } else if (args.length == 2) {
-                return plugin.apply(builder, args[0], args[1]);
-            } else if (args.length == 3) {
-                return plugin.apply(builder, args[0], args[1], args[2]);
-            } else if (args.length == 4) {
-                return plugin.apply(builder, args[0], args[1], args[2], args[3]);
-            } else {
-                throw plugin.invalidHandler(builder, args);
-            }
-        }
-
-        default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext builder, ValueNode... args) {
-            return new GraalInternalError("Invocation plugin %s does not handle invocations with %d arguments", getClass().getSimpleName(), args.length);
-        }
-    }
-
-    /**
-     * Utility for {@linkplain GraphBuilderPlugins#register(ResolvedJavaMethod, InvocationPlugin)
-     * registration} of plugins.
-     */
-    public static class Registration {
-
-        /**
-         * Sentinel class for use with {@link Registration#register1},
-         * {@link Registration#register2} or {@link Registration#register3} to denote the receiver
-         * argument for a non-static method.
-         */
-        public static final class Receiver {
-            private Receiver() {
-                throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-
-        private final GraphBuilderPlugins plugins;
-        private final MetaAccessProvider metaAccess;
-        private final Class<?> declaringClass;
-
-        /**
-         * Creates an object for registering plugins for methods declared by a given class.
-         *
-         * @param plugins where to register the plugins
-         * @param metaAccess used to resolve classes and methods
-         * @param declaringClass the class declaring the methods for which plugins will be
-         *            registered via this object
-         */
-        public Registration(GraphBuilderPlugins plugins, MetaAccessProvider metaAccess, Class<?> declaringClass) {
-            this.plugins = plugins;
-            this.metaAccess = metaAccess;
-            this.declaringClass = declaringClass;
-        }
-
-        /**
-         * Registers a plugin for a method with no arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register0(String name, InvocationPlugin plugin) {
-            plugins.register(resolve(metaAccess, declaringClass, name), plugin);
-        }
-
-        /**
-         * Registers a plugin for a method with 1 argument.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg);
-            plugins.register(method, plugin);
-        }
-
-        /**
-         * Registers a plugin for a method with 2 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2);
-            plugins.register(method, plugin);
-        }
-
-        /**
-         * Registers a plugin for a method with 3 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3);
-            plugins.register(method, plugin);
-        }
-
-        /**
-         * Registers a plugin for a method with 4 arguments.
-         *
-         * @param name the name of the method
-         * @param plugin the plugin to be registered
-         */
-        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
-            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4);
-            plugins.register(method, plugin);
-        }
-
-        /**
-         * Resolves a method given a declaring class, name and parameter types.
-         */
-        public static ResolvedJavaMethod resolve(MetaAccessProvider metaAccess, Class<?> declaringClass, String name, Class<?>... parameterTypes) {
-            try {
-                return metaAccess.lookupJavaMethod(name.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(name, parameterTypes));
-            } catch (NoSuchMethodException | SecurityException e) {
-                throw new GraalInternalError(e);
-            }
-        }
-    }
-
-    public static class InvocationPluginChecker {
-        /**
-         * The set of all {@link InvocationPlugin#apply} method signatures.
-         */
-        static final Class<?>[][] SIGS;
-        static {
-            ArrayList<Class<?>[]> sigs = new ArrayList<>(5);
-            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
-                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
-                    Class<?>[] sig = method.getParameterTypes();
-                    assert sig[0] == GraphBuilderContext.class;
-                    assert Arrays.asList(Arrays.copyOfRange(sig, 1, sig.length)).stream().allMatch(c -> c == ValueNode.class);
-                    while (sigs.size() < sig.length) {
-                        sigs.add(null);
-                    }
-                    sigs.set(sig.length - 1, sig);
-                }
-            }
-            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
-                            ValueNode.class.getSimpleName());
-            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
-        }
-
-        public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) {
-            int arguments = method.getSignature().getParameterCount(!method.isStatic());
-            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)"));
-            Method expected = null;
-            for (Method m : plugin.getClass().getDeclaredMethods()) {
-                if (m.getName().equals("apply")) {
-                    Class<?>[] parameterTypes = m.getParameterTypes();
-                    assert Arrays.equals(SIGS[arguments], parameterTypes) : format("graph builder plugin for %s has wrong signature%nexpected: (%s)%n  actual: (%s)", method.format("%H.%n(%p)"),
-                                    sigString(SIGS[arguments]), sigString(m.getParameterTypes()));
-                    expected = m;
-                }
-            }
-            assert expected != null : format("graph builder plugin %s must define exactly one \"apply\" method, none found", plugin);
-            return true;
-        }
-
-        protected static String sigString(Class<?>... sig) {
-            StringBuilder sb = new StringBuilder();
-            for (Class<?> t : sig) {
-                if (sb.length() != 0) {
-                    sb.append(", ");
-                }
-                sb.append(t.getSimpleName());
-            }
-            return sb.toString();
-        }
-
-    }
-
-    /**
-     * Registers an {@link InvocationPlugin} for a given method. There must be no plugin currently
-     * registered for {@code method}.
-     */
-    void register(ResolvedJavaMethod method, InvocationPlugin plugin);
-
-    /**
-     * Gets the {@link InvocationPlugin} for a given method.
-     *
-     * @param method the method to lookup
-     * @return the plugin associated with {@code method} or {@code null} if none exists
-     */
-    InvocationPlugin lookupInvocation(ResolvedJavaMethod method);
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPluginsProvider.java	Sat Feb 21 19:47:33 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);
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,8 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.java.BciBlockMapping.LocalLiveness;
-import com.oracle.graal.java.GraphBuilderPlugins.ParameterPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -54,8 +53,8 @@
      * @param method the method whose frame is simulated
      * @param graph the target graph of Graal nodes created by the builder
      */
-    public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, Supplier<FrameState> outerFrameStateSupplier) {
-        super(method);
+    public HIRFrameStateBuilder(ResolvedJavaMethod method, StructuredGraph graph, boolean checkTypes, Supplier<FrameState> outerFrameStateSupplier) {
+        super(method, checkTypes);
 
         assert graph != null;
 
@@ -70,14 +69,14 @@
         int index = 0;
         if (!method.isStatic()) {
             // set the receiver
-            storeLocal(javaIndex, arguments[index]);
+            locals[javaIndex] = arguments[index];
             javaIndex = 1;
             index = 1;
         }
         Signature sig = method.getSignature();
         int max = sig.getParameterCount(false);
         for (int i = 0; i < max; i++) {
-            storeLocal(javaIndex, arguments[index]);
+            locals[javaIndex] = arguments[index];
             javaIndex += arguments[index].getKind().getSlotCount();
             index++;
         }
@@ -96,7 +95,7 @@
             if (receiver == null) {
                 receiver = new ParameterNode(javaIndex, StampFactory.declaredNonNull(method.getDeclaringClass()));
             }
-            storeLocal(javaIndex, graph.unique(receiver));
+            locals[javaIndex] = graph.unique(receiver);
             javaIndex = 1;
             index = 1;
         }
@@ -122,7 +121,7 @@
             if (param == null) {
                 param = new ParameterNode(index, stamp);
             }
-            storeLocal(javaIndex, graph.unique(param));
+            locals[javaIndex] = graph.unique(param);
             javaIndex += kind.getSlotCount();
             index++;
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,236 @@
+/*
+ * 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 java.lang.String.*;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Manages a set of {@link InvocationPlugin}s.
+ */
+public class InvocationPlugins {
+    /**
+     * Utility for {@linkplain InvocationPlugins#register(ResolvedJavaMethod, InvocationPlugin)
+     * registration} of invocation plugins.
+     */
+    public static class Registration {
+
+        /**
+         * Sentinel class for use with {@link Registration#register1},
+         * {@link Registration#register2} or {@link Registration#register3} to denote the receiver
+         * argument for a non-static method.
+         */
+        public static final class Receiver {
+            private Receiver() {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+
+        private final InvocationPlugins plugins;
+        private final MetaAccessProvider metaAccess;
+        private final Class<?> declaringClass;
+
+        /**
+         * Creates an object for registering {@link InvocationPlugin}s for methods declared by a
+         * given class.
+         *
+         * @param plugins where to register the plugins
+         * @param metaAccess used to resolve classes and methods
+         * @param declaringClass the class declaring the methods for which plugins will be
+         *            registered via this object
+         */
+        public Registration(InvocationPlugins plugins, MetaAccessProvider metaAccess, Class<?> declaringClass) {
+            this.plugins = plugins;
+            this.metaAccess = metaAccess;
+            this.declaringClass = declaringClass;
+        }
+
+        /**
+         * Registers a plugin for a method with no arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register0(String name, InvocationPlugin plugin) {
+            plugins.register(resolve(metaAccess, declaringClass, name), plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 1 argument.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register1(String name, Class<?> arg, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg == Receiver.class ? resolve(metaAccess, declaringClass, name) : resolve(metaAccess, declaringClass, name, arg);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 2 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register2(String name, Class<?> arg1, Class<?> arg2, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2) : resolve(metaAccess, declaringClass, name, arg1, arg2);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 3 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register3(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Registers a plugin for a method with 4 arguments.
+         *
+         * @param name the name of the method
+         * @param plugin the plugin to be registered
+         */
+        public void register4(String name, Class<?> arg1, Class<?> arg2, Class<?> arg3, Class<?> arg4, InvocationPlugin plugin) {
+            ResolvedJavaMethod method = arg1 == Receiver.class ? resolve(metaAccess, declaringClass, name, arg2, arg3, arg4) : resolve(metaAccess, declaringClass, name, arg1, arg2, arg3, arg4);
+            plugins.register(method, plugin);
+        }
+
+        /**
+         * Resolves a method given a declaring class, name and parameter types.
+         */
+        public static ResolvedJavaMethod resolve(MetaAccessProvider metaAccess, Class<?> declaringClass, String name, Class<?>... parameterTypes) {
+            try {
+                return metaAccess.lookupJavaMethod(name.equals("<init>") ? declaringClass.getDeclaredConstructor(parameterTypes) : declaringClass.getDeclaredMethod(name, parameterTypes));
+            } catch (NoSuchMethodException | SecurityException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+    }
+
+    private final Map<ResolvedJavaMethod, InvocationPlugin> plugins = new HashMap<>();
+
+    /**
+     * The invocation plugins deferred to if a plugin is not found in this object.
+     */
+    private InvocationPlugins defaults;
+
+    /**
+     * Registers an invocation plugin for a given method. There must be no plugin currently
+     * registered for {@code method}.
+     */
+    public void register(ResolvedJavaMethod method, InvocationPlugin plugin) {
+        assert Checker.check(method, plugin);
+        GraphBuilderPlugin oldValue = plugins.put(method, plugin);
+        // System.out.println("registered: " + plugin);
+        assert oldValue == null;
+    }
+
+    /**
+     * Gets the plugin for a given method.
+     *
+     * @param method the method to lookup
+     * @return the plugin associated with {@code method} or {@code null} if none exists
+     */
+    public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) {
+        InvocationPlugin res = plugins.get(method);
+        if (res == null && defaults != null) {
+            return defaults.lookupInvocation(method);
+        }
+        return res;
+    }
+
+    /**
+     * Sets the invocation plugins {@linkplain #lookupInvocation(ResolvedJavaMethod) searched} if a
+     * plugin is not found in this object.
+     */
+    public InvocationPlugins setDefaults(InvocationPlugins defaults) {
+        InvocationPlugins old = this.defaults;
+        this.defaults = defaults;
+        return old;
+    }
+
+    /**
+     * Adds all the plugins from {@code other} to this object.
+     */
+    public void updateFrom(InvocationPlugins other) {
+        this.plugins.putAll(other.plugins);
+        if (other.defaults != null) {
+            updateFrom(other.defaults);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", ")) + " / defaults: " + this.defaults;
+    }
+
+    private static class Checker {
+        /**
+         * The set of all {@link InvocationPlugin#apply} method signatures.
+         */
+        static final Class<?>[][] SIGS;
+        static {
+            ArrayList<Class<?>[]> sigs = new ArrayList<>(5);
+            for (Method method : InvocationPlugin.class.getDeclaredMethods()) {
+                if (!Modifier.isStatic(method.getModifiers()) && method.getName().equals("apply")) {
+                    Class<?>[] sig = method.getParameterTypes();
+                    assert sig[0] == GraphBuilderContext.class;
+                    assert Arrays.asList(Arrays.copyOfRange(sig, 1, sig.length)).stream().allMatch(c -> c == ValueNode.class);
+                    while (sigs.size() < sig.length) {
+                        sigs.add(null);
+                    }
+                    sigs.set(sig.length - 1, sig);
+                }
+            }
+            assert sigs.indexOf(null) == -1 : format("need to add an apply() method to %s that takes %d %s arguments ", InvocationPlugin.class.getName(), sigs.indexOf(null),
+                            ValueNode.class.getSimpleName());
+            SIGS = sigs.toArray(new Class<?>[sigs.size()][]);
+        }
+
+        public static boolean check(ResolvedJavaMethod method, InvocationPlugin plugin) {
+            int arguments = method.getSignature().getParameterCount(!method.isStatic());
+            assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method.format("%H.%n(%p)"));
+            for (Method m : plugin.getClass().getDeclaredMethods()) {
+                if (m.getName().equals("apply")) {
+                    Class<?>[] parameterTypes = m.getParameterTypes();
+                    if (Arrays.equals(SIGS[arguments], parameterTypes)) {
+                        return true;
+                    }
+                }
+            }
+            throw new AssertionError(format("graph builder plugin for %s not found", method.format("%H.%n(%p)")));
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/LargeLocalLiveness.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2009, 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 java.util.*;
+
+import com.oracle.graal.java.BciBlockMapping.*;
+
+public final class LargeLocalLiveness extends LocalLiveness {
+    private BitSet[] localsLiveIn;
+    private BitSet[] localsLiveOut;
+    private BitSet[] localsLiveGen;
+    private BitSet[] localsLiveKill;
+    private BitSet[] localsChangedInLoop;
+
+    public LargeLocalLiveness(BciBlock[] blocks, int maxLocals, int loopCount) {
+        super(blocks);
+        int blocksSize = blocks.length;
+        localsLiveIn = new BitSet[blocksSize];
+        localsLiveOut = new BitSet[blocksSize];
+        localsLiveGen = new BitSet[blocksSize];
+        localsLiveKill = new BitSet[blocksSize];
+        for (int i = 0; i < blocksSize; i++) {
+            localsLiveIn[i] = new BitSet(maxLocals);
+            localsLiveOut[i] = new BitSet(maxLocals);
+            localsLiveGen[i] = new BitSet(maxLocals);
+            localsLiveKill[i] = new BitSet(maxLocals);
+        }
+        localsChangedInLoop = new BitSet[loopCount];
+        for (int i = 0; i < loopCount; ++i) {
+            localsChangedInLoop[i] = new BitSet(maxLocals);
+        }
+    }
+
+    @Override
+    protected String debugLiveIn(int blockID) {
+        return localsLiveIn[blockID].toString();
+    }
+
+    @Override
+    protected String debugLiveOut(int blockID) {
+        return localsLiveOut[blockID].toString();
+    }
+
+    @Override
+    protected String debugLiveGen(int blockID) {
+        return localsLiveGen[blockID].toString();
+    }
+
+    @Override
+    protected String debugLiveKill(int blockID) {
+        return localsLiveKill[blockID].toString();
+    }
+
+    @Override
+    protected int liveOutCardinality(int blockID) {
+        return localsLiveOut[blockID].cardinality();
+    }
+
+    @Override
+    protected void propagateLiveness(int blockID, int successorID) {
+        localsLiveOut[blockID].or(localsLiveIn[successorID]);
+    }
+
+    @Override
+    protected void updateLiveness(int blockID) {
+        BitSet liveIn = localsLiveIn[blockID];
+        liveIn.clear();
+        liveIn.or(localsLiveOut[blockID]);
+        liveIn.andNot(localsLiveKill[blockID]);
+        liveIn.or(localsLiveGen[blockID]);
+    }
+
+    @Override
+    protected void loadOne(int blockID, int local) {
+        if (!localsLiveKill[blockID].get(local)) {
+            localsLiveGen[blockID].set(local);
+        }
+    }
+
+    @Override
+    protected void storeOne(int blockID, int local) {
+        if (!localsLiveGen[blockID].get(local)) {
+            localsLiveKill[blockID].set(local);
+        }
+
+        BciBlock block = blocks[blockID];
+        long tmp = block.loops;
+        int pos = 0;
+        while (tmp != 0) {
+            if ((tmp & 1L) == 1L) {
+                this.localsChangedInLoop[pos].set(local);
+            }
+            tmp >>= 1;
+            ++pos;
+        }
+    }
+
+    @Override
+    public boolean localIsLiveIn(BciBlock block, int local) {
+        return block.getId() >= Integer.MAX_VALUE ? true : localsLiveIn[block.getId()].get(local);
+    }
+
+    @Override
+    public boolean localIsLiveOut(BciBlock block, int local) {
+        return block.getId() >= Integer.MAX_VALUE ? true : localsLiveOut[block.getId()].get(local);
+    }
+
+    @Override
+    public boolean localIsChangedInLoop(int loopId, int local) {
+        return localsChangedInLoop[loopId].get(local);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/LocalLiveness.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2009, 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.bytecode.Bytecodes.*;
+
+import com.oracle.graal.bytecode.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.java.BciBlockMapping.*;
+
+/**
+ * Encapsulates the liveness calculation, so that subclasses for locals &le; 64 and locals &gt; 64
+ * can be implemented.
+ */
+public abstract class LocalLiveness {
+    protected final BciBlock[] blocks;
+
+    public static LocalLiveness compute(BytecodeStream stream, BciBlock[] blocks, int maxLocals, int loopCount) {
+        LocalLiveness liveness = maxLocals <= 64 ? new SmallLocalLiveness(blocks, maxLocals, loopCount) : new LargeLocalLiveness(blocks, maxLocals, loopCount);
+        liveness.computeLiveness(stream);
+        return liveness;
+    }
+
+    protected LocalLiveness(BciBlock[] blocks) {
+        this.blocks = blocks;
+    }
+
+    void computeLiveness(BytecodeStream stream) {
+        for (BciBlock block : blocks) {
+            computeLocalLiveness(stream, block);
+        }
+
+        boolean changed;
+        int iteration = 0;
+        do {
+            Debug.log("Iteration %d", iteration);
+            changed = false;
+            for (int i = blocks.length - 1; i >= 0; i--) {
+                BciBlock block = blocks[i];
+                int blockID = block.getId();
+                // log statements in IFs because debugLiveX creates a new String
+                if (Debug.isLogEnabled()) {
+                    Debug.logv("  start B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
+                                    debugLiveGen(blockID), debugLiveKill(blockID));
+                }
+
+                boolean blockChanged = (iteration == 0);
+                if (block.getSuccessorCount() > 0) {
+                    int oldCardinality = liveOutCardinality(blockID);
+                    for (BciBlock sux : block.getSuccessors()) {
+                        if (Debug.isLogEnabled()) {
+                            Debug.log("    Successor B%d: %s", sux.getId(), debugLiveIn(sux.getId()));
+                        }
+                        propagateLiveness(blockID, sux.getId());
+                    }
+                    blockChanged |= (oldCardinality != liveOutCardinality(blockID));
+                }
+
+                if (blockChanged) {
+                    updateLiveness(blockID);
+                    if (Debug.isLogEnabled()) {
+                        Debug.logv("  end   B%d  [%d, %d]  in: %s  out: %s  gen: %s  kill: %s", block.getId(), block.startBci, block.endBci, debugLiveIn(blockID), debugLiveOut(blockID),
+                                        debugLiveGen(blockID), debugLiveKill(blockID));
+                    }
+                }
+                changed |= blockChanged;
+            }
+            iteration++;
+        } while (changed);
+    }
+
+    /**
+     * Returns whether the local is live at the beginning of the given block.
+     */
+    public abstract boolean localIsLiveIn(BciBlock block, int local);
+
+    /**
+     * Returns whether the local is set in the given loop.
+     */
+    public abstract boolean localIsChangedInLoop(int loopId, int local);
+
+    /**
+     * Returns whether the local is live at the end of the given block.
+     */
+    public abstract boolean localIsLiveOut(BciBlock block, int local);
+
+    /**
+     * Returns a string representation of the liveIn values of the given block.
+     */
+    protected abstract String debugLiveIn(int blockID);
+
+    /**
+     * Returns a string representation of the liveOut values of the given block.
+     */
+    protected abstract String debugLiveOut(int blockID);
+
+    /**
+     * Returns a string representation of the liveGen values of the given block.
+     */
+    protected abstract String debugLiveGen(int blockID);
+
+    /**
+     * Returns a string representation of the liveKill values of the given block.
+     */
+    protected abstract String debugLiveKill(int blockID);
+
+    /**
+     * Returns the number of live locals at the end of the given block.
+     */
+    protected abstract int liveOutCardinality(int blockID);
+
+    /**
+     * Adds all locals the are in the liveIn of the successor to the liveOut of the block.
+     */
+    protected abstract void propagateLiveness(int blockID, int successorID);
+
+    /**
+     * Calculates a new liveIn for the given block from liveOut, liveKill and liveGen.
+     */
+    protected abstract void updateLiveness(int blockID);
+
+    /**
+     * Adds the local to liveGen if it wasn't already killed in this block.
+     */
+    protected abstract void loadOne(int blockID, int local);
+
+    /**
+     * Add this local to liveKill if it wasn't already generated in this block.
+     */
+    protected abstract void storeOne(int blockID, int local);
+
+    private void computeLocalLiveness(BytecodeStream stream, BciBlock block) {
+        if (block.startBci < 0 || block.endBci < 0) {
+            return;
+        }
+        int blockID = block.getId();
+        int localIndex;
+        stream.setBCI(block.startBci);
+        while (stream.currentBCI() <= block.endBci) {
+            switch (stream.currentBC()) {
+                case LLOAD:
+                case DLOAD:
+                    loadTwo(blockID, stream.readLocalIndex());
+                    break;
+                case LLOAD_0:
+                case DLOAD_0:
+                    loadTwo(blockID, 0);
+                    break;
+                case LLOAD_1:
+                case DLOAD_1:
+                    loadTwo(blockID, 1);
+                    break;
+                case LLOAD_2:
+                case DLOAD_2:
+                    loadTwo(blockID, 2);
+                    break;
+                case LLOAD_3:
+                case DLOAD_3:
+                    loadTwo(blockID, 3);
+                    break;
+                case IINC:
+                    localIndex = stream.readLocalIndex();
+                    loadOne(blockID, localIndex);
+                    storeOne(blockID, localIndex);
+                    break;
+                case ILOAD:
+                case FLOAD:
+                case ALOAD:
+                case RET:
+                    loadOne(blockID, stream.readLocalIndex());
+                    break;
+                case ILOAD_0:
+                case FLOAD_0:
+                case ALOAD_0:
+                    loadOne(blockID, 0);
+                    break;
+                case ILOAD_1:
+                case FLOAD_1:
+                case ALOAD_1:
+                    loadOne(blockID, 1);
+                    break;
+                case ILOAD_2:
+                case FLOAD_2:
+                case ALOAD_2:
+                    loadOne(blockID, 2);
+                    break;
+                case ILOAD_3:
+                case FLOAD_3:
+                case ALOAD_3:
+                    loadOne(blockID, 3);
+                    break;
+
+                case LSTORE:
+                case DSTORE:
+                    storeTwo(blockID, stream.readLocalIndex());
+                    break;
+                case LSTORE_0:
+                case DSTORE_0:
+                    storeTwo(blockID, 0);
+                    break;
+                case LSTORE_1:
+                case DSTORE_1:
+                    storeTwo(blockID, 1);
+                    break;
+                case LSTORE_2:
+                case DSTORE_2:
+                    storeTwo(blockID, 2);
+                    break;
+                case LSTORE_3:
+                case DSTORE_3:
+                    storeTwo(blockID, 3);
+                    break;
+                case ISTORE:
+                case FSTORE:
+                case ASTORE:
+                    storeOne(blockID, stream.readLocalIndex());
+                    break;
+                case ISTORE_0:
+                case FSTORE_0:
+                case ASTORE_0:
+                    storeOne(blockID, 0);
+                    break;
+                case ISTORE_1:
+                case FSTORE_1:
+                case ASTORE_1:
+                    storeOne(blockID, 1);
+                    break;
+                case ISTORE_2:
+                case FSTORE_2:
+                case ASTORE_2:
+                    storeOne(blockID, 2);
+                    break;
+                case ISTORE_3:
+                case FSTORE_3:
+                case ASTORE_3:
+                    storeOne(blockID, 3);
+                    break;
+            }
+            stream.next();
+        }
+    }
+
+    private void loadTwo(int blockID, int local) {
+        loadOne(blockID, local);
+        loadOne(blockID, local + 1);
+    }
+
+    private void storeTwo(int blockID, int local) {
+        storeOne(blockID, local);
+        storeOne(blockID, local + 1);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/SmallLocalLiveness.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2009, 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.java.BciBlockMapping.*;
+
+public final class SmallLocalLiveness extends LocalLiveness {
+    /*
+     * local n is represented by the bit accessible as (1 << n)
+     */
+
+    private final long[] localsLiveIn;
+    private final long[] localsLiveOut;
+    private final long[] localsLiveGen;
+    private final long[] localsLiveKill;
+    private final long[] localsChangedInLoop;
+    private final int maxLocals;
+
+    public SmallLocalLiveness(BciBlock[] blocks, int maxLocals, int loopCount) {
+        super(blocks);
+        this.maxLocals = maxLocals;
+        int blockSize = blocks.length;
+        localsLiveIn = new long[blockSize];
+        localsLiveOut = new long[blockSize];
+        localsLiveGen = new long[blockSize];
+        localsLiveKill = new long[blockSize];
+        localsChangedInLoop = new long[loopCount];
+    }
+
+    private String debugString(long value) {
+        StringBuilder str = new StringBuilder("{");
+        long current = value;
+        for (int i = 0; i < maxLocals; i++) {
+            if ((current & 1L) == 1L) {
+                if (str.length() > 1) {
+                    str.append(", ");
+                }
+                str.append(i);
+            }
+            current >>= 1;
+        }
+        return str.append('}').toString();
+    }
+
+    @Override
+    protected String debugLiveIn(int blockID) {
+        return debugString(localsLiveIn[blockID]);
+    }
+
+    @Override
+    protected String debugLiveOut(int blockID) {
+        return debugString(localsLiveOut[blockID]);
+    }
+
+    @Override
+    protected String debugLiveGen(int blockID) {
+        return debugString(localsLiveGen[blockID]);
+    }
+
+    @Override
+    protected String debugLiveKill(int blockID) {
+        return debugString(localsLiveKill[blockID]);
+    }
+
+    @Override
+    protected int liveOutCardinality(int blockID) {
+        return Long.bitCount(localsLiveOut[blockID]);
+    }
+
+    @Override
+    protected void propagateLiveness(int blockID, int successorID) {
+        localsLiveOut[blockID] |= localsLiveIn[successorID];
+    }
+
+    @Override
+    protected void updateLiveness(int blockID) {
+        localsLiveIn[blockID] = (localsLiveOut[blockID] & ~localsLiveKill[blockID]) | localsLiveGen[blockID];
+    }
+
+    @Override
+    protected void loadOne(int blockID, int local) {
+        long bit = 1L << local;
+        if ((localsLiveKill[blockID] & bit) == 0L) {
+            localsLiveGen[blockID] |= bit;
+        }
+    }
+
+    @Override
+    protected void storeOne(int blockID, int local) {
+        long bit = 1L << local;
+        if ((localsLiveGen[blockID] & bit) == 0L) {
+            localsLiveKill[blockID] |= bit;
+        }
+
+        BciBlock block = blocks[blockID];
+        long tmp = block.loops;
+        int pos = 0;
+        while (tmp != 0) {
+            if ((tmp & 1L) == 1L) {
+                this.localsChangedInLoop[pos] |= bit;
+            }
+            tmp >>= 1;
+            ++pos;
+        }
+    }
+
+    @Override
+    public boolean localIsLiveIn(BciBlock block, int local) {
+        int blockID = block.getId();
+        return blockID >= Integer.MAX_VALUE ? false : (localsLiveIn[blockID] & (1L << local)) != 0L;
+    }
+
+    @Override
+    public boolean localIsLiveOut(BciBlock block, int local) {
+        int blockID = block.getId();
+        return blockID >= Integer.MAX_VALUE ? false : (localsLiveOut[blockID] & (1L << local)) != 0L;
+    }
+
+    @Override
+    public boolean localIsChangedInLoop(int loopId, int local) {
+        return (localsChangedInLoop[loopId] & (1L << local)) != 0L;
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/StandardGraphBuilderPluginsProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +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) {
-            builder.push(kind.getStackKind(), builder.append(new UnboxNode(nullCheckedValue(builder, value), kind)));
-            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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Sat Feb 21 19:55:33 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.jtt/src/com/oracle/graal/jtt/except/UntrustedInterfaces.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/UntrustedInterfaces.java	Sat Feb 21 19:55:33 2015 +0100
@@ -45,20 +45,20 @@
      *     public void setField() {
      *         field = new TestConstant();
      *     }
-     * 
+     *
      *     public void setStaticField() {
      *         staticField = new TestConstant();
      *     }
-     * 
+     *
      *     public int callMe(CallBack callback) {
      *         return callback.callBack(new TestConstant());
      *     }
-     * 
+     *
      *     public TestInterface get() {
      *         return new TestConstant();
      *     }
      * }
-     * 
+     *
      * private static final class TestConstant implements TestInterface {
      *     public int method() {
      *         return 42;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6753639.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6753639.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
  * @test
  * @bug 6753639
  * @summary Strange optimisation in for loop with cyclic integer condition
- * 
+ *
  * @run main/othervm -Xbatch Test6753639
  */
 // @formatter:off
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/LongToSomethingArray01.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/LongToSomethingArray01.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,7 +28,7 @@
 
 /**
  * inspired by java.security.SecureRandom.longToByteArray(long).
- * 
+ *
  */
 public class LongToSomethingArray01 extends JTTTest {
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 
 public final class AMD64AddressValue extends CompositeValue {
+    public static final CompositeValueClass<AMD64AddressValue> TYPE = CompositeValueClass.create(AMD64AddressValue.class);
 
     private static final long serialVersionUID = -4444600052487578694L;
 
@@ -46,7 +47,7 @@
     }
 
     public AMD64AddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, Scale scale, int displacement) {
-        super(kind);
+        super(TYPE, kind);
         this.base = base;
         this.index = index;
         this.scale = scale;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Sat Feb 21 19:55:33 2015 +0100
@@ -63,13 +63,15 @@
     /**
      * Unary operation with separate source and destination operand.
      */
-    public static class Unary2Op extends AMD64LIRInstruction {
+    public static final class Unary2Op extends AMD64LIRInstruction {
 
+        public static final LIRInstructionClass<Unary2Op> TYPE = LIRInstructionClass.create(Unary2Op.class);
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG}) protected AllocatableValue result;
         @Use({REG, STACK}) protected AllocatableValue x;
 
         public Unary2Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -84,13 +86,15 @@
     /**
      * Unary operation with separate source and destination operand but register only.
      */
-    public static class Unary2RegOp extends AMD64LIRInstruction {
+    public static final class Unary2RegOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<Unary2RegOp> TYPE = LIRInstructionClass.create(Unary2RegOp.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG}) protected AllocatableValue result;
         @Use({REG}) protected AllocatableValue x;
 
         public Unary2RegOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -106,12 +110,14 @@
      * Unary operation with single operand for source and destination.
      */
     public static class Unary1Op extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<Unary1Op> TYPE = LIRInstructionClass.create(Unary1Op.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
         @Use({REG, STACK}) protected AllocatableValue x;
 
         public Unary1Op(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -127,13 +133,14 @@
     /**
      * Unary operation with separate memory source and destination operand.
      */
-    public static class Unary2MemoryOp extends MemOp {
+    public static final class Unary2MemoryOp extends MemOp {
+        public static final LIRInstructionClass<Unary2MemoryOp> TYPE = LIRInstructionClass.create(Unary2MemoryOp.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG}) protected AllocatableValue result;
 
         public Unary2MemoryOp(AMD64Arithmetic opcode, AllocatableValue result, Kind kind, AMD64AddressValue address, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.opcode = opcode;
             this.result = result;
         }
@@ -149,6 +156,7 @@
      * destination. The second source operand may be a stack slot.
      */
     public static class BinaryRegStack extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BinaryRegStack> TYPE = LIRInstructionClass.create(BinaryRegStack.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -156,6 +164,7 @@
         @Alive({REG, STACK}) protected AllocatableValue y;
 
         public BinaryRegStack(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -180,7 +189,8 @@
      * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand may be a stack slot.
      */
-    public static class BinaryMemory extends AMD64LIRInstruction {
+    public static final class BinaryMemory extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BinaryMemory> TYPE = LIRInstructionClass.create(BinaryMemory.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -190,6 +200,7 @@
         @State protected LIRFrameState state;
 
         public BinaryMemory(AMD64Arithmetic opcode, Kind kind, AllocatableValue result, AllocatableValue x, AMD64AddressValue location, LIRFrameState state) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -219,7 +230,8 @@
      * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand must be a register.
      */
-    public static class BinaryRegReg extends AMD64LIRInstruction {
+    public static final class BinaryRegReg extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BinaryRegReg> TYPE = LIRInstructionClass.create(BinaryRegReg.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -227,6 +239,7 @@
         @Alive({REG}) protected AllocatableValue y;
 
         public BinaryRegReg(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -250,7 +263,8 @@
     /**
      * Binary operation with single source/destination operand and one constant.
      */
-    public static class BinaryRegConst extends AMD64LIRInstruction {
+    public static final class BinaryRegConst extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BinaryRegConst> TYPE = LIRInstructionClass.create(BinaryRegConst.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -258,6 +272,7 @@
         protected JavaConstant y;
 
         public BinaryRegConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -281,7 +296,8 @@
      * Commutative binary operation with two operands. One of the operands is combined with the
      * result.
      */
-    public static class BinaryCommutative extends AMD64LIRInstruction {
+    public static final class BinaryCommutative extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BinaryCommutative> TYPE = LIRInstructionClass.create(BinaryCommutative.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -289,6 +305,7 @@
         @Use({REG, STACK}) protected AllocatableValue y;
 
         public BinaryCommutative(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -315,7 +332,8 @@
     /**
      * Binary operation with separate source and destination and one constant operand.
      */
-    public static class BinaryRegStackConst extends AMD64LIRInstruction {
+    public static final class BinaryRegStackConst extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<BinaryRegStackConst> TYPE = LIRInstructionClass.create(BinaryRegStackConst.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG}) protected AllocatableValue result;
@@ -323,6 +341,7 @@
         protected JavaConstant y;
 
         public BinaryRegStackConst(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -364,7 +383,8 @@
         }
     }
 
-    public static class MulHighOp extends AMD64LIRInstruction {
+    public static final class MulHighOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MulHighOp> TYPE = LIRInstructionClass.create(MulHighOp.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def({REG}) public AllocatableValue lowResult;
@@ -373,6 +393,7 @@
         @Use({REG, STACK}) public AllocatableValue y;
 
         public MulHighOp(AMD64Arithmetic opcode, LIRKind kind, AllocatableValue y) {
+            super(TYPE);
             this.opcode = opcode;
             this.x = AMD64.rax.asValue(kind);
             this.y = y;
@@ -420,7 +441,8 @@
         }
     }
 
-    public static class DivRemOp extends AMD64LIRInstruction {
+    public static final class DivRemOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<DivRemOp> TYPE = LIRInstructionClass.create(DivRemOp.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def public AllocatableValue divResult;
@@ -430,6 +452,7 @@
         @State protected LIRFrameState state;
 
         public DivRemOp(AMD64Arithmetic opcode, AllocatableValue x, AllocatableValue y, LIRFrameState state) {
+            super(TYPE);
             this.opcode = opcode;
             this.divResult = AMD64.rax.asValue(LIRKind.derive(x, y));
             this.remResult = AMD64.rdx.asValue(LIRKind.derive(x, y));
@@ -456,6 +479,7 @@
     }
 
     public static class FPDivRemOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<FPDivRemOp> TYPE = LIRInstructionClass.create(FPDivRemOp.class);
 
         @Opcode private final AMD64Arithmetic opcode;
         @Def protected AllocatableValue result;
@@ -464,6 +488,7 @@
         @Temp protected AllocatableValue raxTemp;
 
         public FPDivRemOp(AMD64Arithmetic opcode, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.raxTemp = AMD64.rax.asValue(LIRKind.value(Kind.Int));
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,8 @@
  * instructions specialized code is emitted to leverage these instructions.
  */
 @Opcode("ARRAY_EQUALS")
-public class AMD64ArrayEqualsOp extends AMD64LIRInstruction {
+public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ArrayEqualsOp> TYPE = LIRInstructionClass.create(AMD64ArrayEqualsOp.class);
 
     private final Kind kind;
     private final int arrayBaseOffset;
@@ -63,6 +64,7 @@
     @Temp({REG, ILLEGAL}) protected Value vectorTemp2;
 
     public AMD64ArrayEqualsOp(LIRGeneratorTool tool, Kind kind, Value result, Value array1, Value array2, Value length) {
+        super(TYPE);
         this.kind = kind;
 
         Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,7 +28,8 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
-public class AMD64BitManipulationOp extends AMD64LIRInstruction {
+public final class AMD64BitManipulationOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BitManipulationOp> TYPE = LIRInstructionClass.create(AMD64BitManipulationOp.class);
 
     public enum IntrinsicOpcode {
         IPOPCNT,
@@ -47,6 +48,7 @@
     @Use({OperandFlag.REG, OperandFlag.STACK}) protected AllocatableValue input;
 
     public AMD64BitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input) {
+        super(TYPE);
         this.opcode = opcode;
         this.result = result;
         this.input = input;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BreakpointOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BreakpointOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -33,7 +33,8 @@
  * Emits a breakpoint.
  */
 @Opcode("BREAKPOINT")
-public class AMD64BreakpointOp extends AMD64LIRInstruction {
+public final class AMD64BreakpointOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64BreakpointOp> TYPE = LIRInstructionClass.create(AMD64BreakpointOp.class);
 
     /**
      * A set of values loaded into the Java ABI parameter locations (for inspection by a debugger).
@@ -41,6 +42,7 @@
     @Use({REG, STACK}) protected Value[] parameters;
 
     public AMD64BreakpointOp(Value[] parameters) {
+        super(TYPE);
         this.parameters = parameters;
     }
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ByteSwapOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ByteSwapOp.java	Sat Feb 21 19:55:33 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
@@ -29,12 +29,14 @@
 import com.oracle.graal.lir.asm.*;
 
 @Opcode("BSWAP")
-public class AMD64ByteSwapOp extends AMD64LIRInstruction {
+public final class AMD64ByteSwapOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64ByteSwapOp> TYPE = LIRInstructionClass.create(AMD64ByteSwapOp.class);
 
     @Def({OperandFlag.REG, OperandFlag.HINT}) protected Value result;
     @Use protected Value input;
 
     public AMD64ByteSwapOp(Value result, Value input) {
+        super(TYPE);
         this.result = result;
         this.input = input;
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CCall.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CCall.java	Sat Feb 21 19:55:33 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
@@ -27,9 +27,11 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
-public class AMD64CCall extends AMD64LIRInstruction {
+public final class AMD64CCall extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64CCall> TYPE = LIRInstructionClass.create(AMD64CCall.class);
 
     @Def({REG, ILLEGAL}) protected Value result;
     @Use({REG, STACK}) protected Value[] parameters;
@@ -37,6 +39,7 @@
     @Use({REG}) protected Value numberOfFloatingPointArguments;
 
     public AMD64CCall(Value result, Value functionPtr, Value numberOfFloatingPointArguments, Value[] parameters) {
+        super(TYPE);
         this.result = result;
         this.functionPtr = functionPtr;
         this.parameters = parameters;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,13 +36,15 @@
 public class AMD64Call {
 
     public abstract static class CallOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
 
         @Def({REG, ILLEGAL}) protected Value result;
         @Use({REG, STACK}) protected Value[] parameters;
         @Temp protected Value[] temps;
         @State protected LIRFrameState state;
 
-        public CallOp(Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+        protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c);
             this.result = result;
             this.parameters = parameters;
             this.state = state;
@@ -57,21 +59,23 @@
     }
 
     public abstract static class MethodCallOp extends CallOp {
+        public static final LIRInstructionClass<MethodCallOp> TYPE = LIRInstructionClass.create(MethodCallOp.class);
 
         protected final ResolvedJavaMethod callTarget;
 
-        public MethodCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(result, parameters, temps, state);
+        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
             this.callTarget = callTarget;
         }
 
     }
 
     @Opcode("CALL_DIRECT")
-    public static class DirectCallOp extends MethodCallOp {
+    public abstract static class DirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
 
-        public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+        protected DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
         }
 
         @Override
@@ -82,11 +86,17 @@
 
     @Opcode("CALL_INDIRECT")
     public static class IndirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class);
 
         @Use({REG}) protected Value targetAddress;
 
         public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+            this(TYPE, callTarget, result, parameters, temps, targetAddress, state);
+        }
+
+        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
+                        LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
             this.targetAddress = targetAddress;
         }
 
@@ -103,11 +113,12 @@
     }
 
     public abstract static class ForeignCallOp extends CallOp {
+        public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class);
 
         protected final ForeignCallLinkage callTarget;
 
-        public ForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(result, parameters, temps, state);
+        public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
             this.callTarget = callTarget;
         }
 
@@ -118,10 +129,11 @@
     }
 
     @Opcode("NEAR_FOREIGN_CALL")
-    public static class DirectNearForeignCallOp extends ForeignCallOp {
+    public static final class DirectNearForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
 
         public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(linkage, result, parameters, temps, state);
+            super(TYPE, linkage, result, parameters, temps, state);
         }
 
         @Override
@@ -131,12 +143,13 @@
     }
 
     @Opcode("FAR_FOREIGN_CALL")
-    public static class DirectFarForeignCallOp extends ForeignCallOp {
+    public static final class DirectFarForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
 
         @Temp({REG}) protected AllocatableValue callTemp;
 
         public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+            super(TYPE, callTarget, result, parameters, temps, state);
             /*
              * The register allocator does not support virtual registers that are used at the call
              * site, so use a fixed register.
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Sat Feb 21 19:55:33 2015 +0100
@@ -42,12 +42,14 @@
     FCMP,
     DCMP;
 
-    public static class CompareOp extends AMD64LIRInstruction {
+    public static final class CompareOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompareOp> TYPE = LIRInstructionClass.create(CompareOp.class);
         @Opcode private final AMD64Compare opcode;
         @Use({REG}) protected Value x;
         @Use({REG, STACK, CONST}) protected Value y;
 
         public CompareOp(AMD64Compare opcode, Value x, Value y) {
+            super(TYPE);
             this.opcode = opcode;
             this.x = x;
             this.y = y;
@@ -70,7 +72,8 @@
         }
     }
 
-    public static class CompareMemoryOp extends MemOp {
+    public static final class CompareMemoryOp extends MemOp {
+        public static final LIRInstructionClass<CompareMemoryOp> TYPE = LIRInstructionClass.create(CompareMemoryOp.class);
         @Opcode private final AMD64Compare opcode;
         @Use({REG, CONST}) protected Value y;
 
@@ -78,7 +81,7 @@
          * Compare memory, constant or register, memory.
          */
         public CompareMemoryOp(AMD64Compare opcode, Kind kind, AMD64AddressValue address, Value y, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.opcode = opcode;
             this.y = y;
         }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,14 +38,17 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
+import com.oracle.graal.lir.amd64.AMD64Call.CallOp;
 import com.oracle.graal.lir.asm.*;
 
 public class AMD64ControlFlow {
 
-    public static class ReturnOp extends AMD64LIRInstruction implements BlockEndOp {
+    public static final class ReturnOp extends AMD64LIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
         @Use({REG, ILLEGAL}) protected Value x;
 
         public ReturnOp(Value x) {
+            super(TYPE);
             this.x = x;
         }
 
@@ -57,6 +60,7 @@
     }
 
     public static class BranchOp extends AMD64LIRInstruction implements StandardOp.BranchOp {
+        public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
         protected final ConditionFlag condition;
         protected final LabelRef trueDestination;
         protected final LabelRef falseDestination;
@@ -68,6 +72,11 @@
         }
 
         public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            this(TYPE, condition, trueDestination, falseDestination, trueDestinationProbability);
+        }
+
+        protected BranchOp(LIRInstructionClass<? extends BranchOp> c, ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
+            super(c);
             this.condition = condition;
             this.trueDestination = trueDestination;
             this.falseDestination = falseDestination;
@@ -102,11 +111,12 @@
         }
     }
 
-    public static class FloatBranchOp extends BranchOp {
+    public static final class FloatBranchOp extends BranchOp {
+        public static final LIRInstructionClass<FloatBranchOp> TYPE = LIRInstructionClass.create(FloatBranchOp.class);
         protected boolean unorderedIsTrue;
 
         public FloatBranchOp(Condition condition, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination, double trueDestinationProbability) {
-            super(floatCond(condition), trueDestination, falseDestination, trueDestinationProbability);
+            super(TYPE, floatCond(condition), trueDestination, falseDestination, trueDestinationProbability);
             this.unorderedIsTrue = unorderedIsTrue;
         }
 
@@ -116,7 +126,8 @@
         }
     }
 
-    public static class StrategySwitchOp extends AMD64LIRInstruction implements BlockEndOp {
+    public static final class StrategySwitchOp extends AMD64LIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<StrategySwitchOp> TYPE = LIRInstructionClass.create(StrategySwitchOp.class);
         @Use({CONST}) protected JavaConstant[] keyConstants;
         private final LabelRef[] keyTargets;
         private LabelRef defaultTarget;
@@ -125,6 +136,7 @@
         private final SwitchStrategy strategy;
 
         public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            super(TYPE);
             this.strategy = strategy;
             this.keyConstants = strategy.keyConstants;
             this.keyTargets = keyTargets;
@@ -170,7 +182,8 @@
         }
     }
 
-    public static class TableSwitchOp extends AMD64LIRInstruction implements BlockEndOp {
+    public static final class TableSwitchOp extends AMD64LIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<TableSwitchOp> TYPE = LIRInstructionClass.create(TableSwitchOp.class);
         private final int lowKey;
         private final LabelRef defaultTarget;
         private final LabelRef[] targets;
@@ -179,6 +192,7 @@
         @Temp protected Value scratch;
 
         public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Value index, Variable scratch, Variable idxScratch) {
+            super(TYPE);
             this.lowKey = lowKey;
             this.defaultTarget = defaultTarget;
             this.targets = targets;
@@ -254,13 +268,15 @@
     }
 
     @Opcode("CMOVE")
-    public static class CondMoveOp extends AMD64LIRInstruction {
+    public static final class CondMoveOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
         @Def({REG, HINT}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Use({REG, STACK, CONST}) protected Value falseValue;
         private final ConditionFlag condition;
 
         public CondMoveOp(Variable result, Condition condition, AllocatableValue trueValue, Value falseValue) {
+            super(TYPE);
             this.result = result;
             this.condition = intCond(condition);
             this.trueValue = trueValue;
@@ -274,7 +290,8 @@
     }
 
     @Opcode("CMOVE")
-    public static class FloatCondMoveOp extends AMD64LIRInstruction {
+    public static final class FloatCondMoveOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<FloatCondMoveOp> TYPE = LIRInstructionClass.create(FloatCondMoveOp.class);
         @Def({REG}) protected Value result;
         @Alive({REG}) protected Value trueValue;
         @Alive({REG}) protected Value falseValue;
@@ -282,6 +299,7 @@
         private final boolean unorderedIsTrue;
 
         public FloatCondMoveOp(Variable result, Condition condition, boolean unorderedIsTrue, Variable trueValue, Variable falseValue) {
+            super(TYPE);
             this.result = result;
             this.condition = floatCond(condition);
             this.unorderedIsTrue = unorderedIsTrue;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,7 +36,7 @@
  *
  * <pre>
  *   Base       Contents
- * 
+ *
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64LIRInstruction.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64LIRInstruction.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,7 +29,12 @@
 /**
  * Convenience class to provide AMD64MacroAssembler for the {@link #emitCode} method.
  */
-public abstract class AMD64LIRInstruction extends LIRInstructionBase {
+public abstract class AMD64LIRInstruction extends LIRInstruction {
+    public static final LIRInstructionClass<AMD64LIRInstruction> TYPE = LIRInstructionClass.create(AMD64LIRInstruction.class);
+
+    protected AMD64LIRInstruction(LIRInstructionClass<? extends AMD64LIRInstruction> c) {
+        super(c);
+    }
 
     @Override
     public final void emitCode(CompilationResultBuilder crb) {
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MathIntrinsicOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MathIntrinsicOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,7 +31,8 @@
 import com.oracle.graal.lir.asm.*;
 
 // @formatter:off
-public class AMD64MathIntrinsicOp extends AMD64LIRInstruction {
+public final class AMD64MathIntrinsicOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64MathIntrinsicOp> TYPE = LIRInstructionClass.create(AMD64MathIntrinsicOp.class);
     public enum IntrinsicOpcode  {
         SIN, COS, TAN,
         LOG, LOG10
@@ -42,6 +43,7 @@
     @Use protected Value input;
 
     public AMD64MathIntrinsicOp(IntrinsicOpcode opcode, Value result, Value input) {
+        super(TYPE);
         this.opcode = opcode;
         this.result = result;
         this.input = input;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -42,10 +42,12 @@
 public class AMD64Move {
 
     private abstract static class AbstractMoveOp extends AMD64LIRInstruction implements MoveOp {
+        public static final LIRInstructionClass<AbstractMoveOp> TYPE = LIRInstructionClass.create(AbstractMoveOp.class);
 
         private Kind moveKind;
 
-        public AbstractMoveOp(Kind moveKind) {
+        protected AbstractMoveOp(LIRInstructionClass<? extends AbstractMoveOp> c, Kind moveKind) {
+            super(c);
             if (moveKind == Kind.Illegal) {
                 // unknown operand size, conservatively move the whole register
                 this.moveKind = Kind.Long;
@@ -61,13 +63,14 @@
     }
 
     @Opcode("MOVE")
-    public static class MoveToRegOp extends AbstractMoveOp {
+    public static final class MoveToRegOp extends AbstractMoveOp {
+        public static final LIRInstructionClass<MoveToRegOp> TYPE = LIRInstructionClass.create(MoveToRegOp.class);
 
         @Def({REG, HINT}) protected AllocatableValue result;
         @Use({REG, STACK, CONST}) protected Value input;
 
         public MoveToRegOp(Kind moveKind, AllocatableValue result, Value input) {
-            super(moveKind);
+            super(TYPE, moveKind);
             this.result = result;
             this.input = input;
         }
@@ -84,13 +87,14 @@
     }
 
     @Opcode("MOVE")
-    public static class MoveFromRegOp extends AbstractMoveOp {
+    public static final class MoveFromRegOp extends AbstractMoveOp {
+        public static final LIRInstructionClass<MoveFromRegOp> TYPE = LIRInstructionClass.create(MoveFromRegOp.class);
 
         @Def({REG, STACK}) protected AllocatableValue result;
         @Use({REG, CONST, HINT}) protected Value input;
 
         public MoveFromRegOp(Kind moveKind, AllocatableValue result, Value input) {
-            super(moveKind);
+            super(TYPE, moveKind);
             this.result = result;
             this.input = input;
         }
@@ -107,12 +111,14 @@
     }
 
     public abstract static class MemOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemOp> TYPE = LIRInstructionClass.create(MemOp.class);
 
         protected final Kind kind;
         @Use({COMPOSITE}) protected AMD64AddressValue address;
         @State protected LIRFrameState state;
 
-        public MemOp(Kind kind, AMD64AddressValue address, LIRFrameState state) {
+        public MemOp(LIRInstructionClass<? extends MemOp> c, Kind kind, AMD64AddressValue address, LIRFrameState state) {
+            super(c);
             this.kind = kind;
             this.address = address;
             this.state = state;
@@ -137,12 +143,13 @@
         }
     }
 
-    public static class LoadOp extends MemOp {
+    public static final class LoadOp extends MemOp {
+        public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class);
 
         @Def({REG}) protected AllocatableValue result;
 
         public LoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.result = result;
         }
 
@@ -182,12 +189,13 @@
         }
     }
 
-    public static class ZeroExtendLoadOp extends MemOp {
+    public static final class ZeroExtendLoadOp extends MemOp {
+        public static final LIRInstructionClass<ZeroExtendLoadOp> TYPE = LIRInstructionClass.create(ZeroExtendLoadOp.class);
 
         @Def({REG}) protected AllocatableValue result;
 
         public ZeroExtendLoadOp(Kind kind, AllocatableValue result, AMD64AddressValue address, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.result = result;
         }
 
@@ -214,12 +222,13 @@
         }
     }
 
-    public static class StoreOp extends MemOp {
+    public static final class StoreOp extends MemOp {
+        public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class);
 
         @Use({REG}) protected AllocatableValue input;
 
         public StoreOp(Kind kind, AMD64AddressValue address, AllocatableValue input, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.input = input;
         }
 
@@ -256,12 +265,13 @@
         }
     }
 
-    public static class StoreConstantOp extends MemOp {
+    public abstract static class StoreConstantOp extends MemOp {
+        public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class);
 
         protected final JavaConstant input;
 
-        public StoreConstantOp(Kind kind, AMD64AddressValue address, JavaConstant input, LIRFrameState state) {
-            super(kind, address, state);
+        protected StoreConstantOp(LIRInstructionClass<? extends StoreConstantOp> c, Kind kind, AMD64AddressValue address, JavaConstant input, LIRFrameState state) {
+            super(c, kind, address, state);
             this.input = input;
         }
 
@@ -304,12 +314,14 @@
         }
     }
 
-    public static class LeaOp extends AMD64LIRInstruction {
+    public static final class LeaOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<LeaOp> TYPE = LIRInstructionClass.create(LeaOp.class);
 
         @Def({REG}) protected AllocatableValue result;
         @Use({COMPOSITE, UNINITIALIZED}) protected AMD64AddressValue address;
 
         public LeaOp(AllocatableValue result, AMD64AddressValue address) {
+            super(TYPE);
             this.result = result;
             this.address = address;
         }
@@ -320,12 +332,14 @@
         }
     }
 
-    public static class LeaDataOp extends AMD64LIRInstruction {
+    public static final class LeaDataOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<LeaDataOp> TYPE = LIRInstructionClass.create(LeaDataOp.class);
 
         @Def({REG}) protected AllocatableValue result;
         private final byte[] data;
 
         public LeaDataOp(AllocatableValue result, byte[] data) {
+            super(TYPE);
             this.result = result;
             this.data = data;
         }
@@ -336,12 +350,14 @@
         }
     }
 
-    public static class StackLeaOp extends AMD64LIRInstruction {
+    public static final class StackLeaOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<StackLeaOp> TYPE = LIRInstructionClass.create(StackLeaOp.class);
 
         @Def({REG}) protected AllocatableValue result;
         @Use({STACK, UNINITIALIZED}) protected StackSlotValue slot;
 
         public StackLeaOp(AllocatableValue result, StackSlotValue slot) {
+            super(TYPE);
             assert isStackSlotValue(slot) : "Not a stack slot: " + slot;
             this.result = result;
             this.slot = slot;
@@ -353,11 +369,13 @@
         }
     }
 
-    public static class MembarOp extends AMD64LIRInstruction {
+    public static final class MembarOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
 
         private final int barriers;
 
         public MembarOp(final int barriers) {
+            super(TYPE);
             this.barriers = barriers;
         }
 
@@ -367,12 +385,14 @@
         }
     }
 
-    public static class NullCheckOp extends AMD64LIRInstruction implements NullCheck {
+    public static final class NullCheckOp extends AMD64LIRInstruction implements NullCheck {
+        public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
 
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
 
         public NullCheckOp(Variable input, LIRFrameState state) {
+            super(TYPE);
             this.input = input;
             this.state = state;
         }
@@ -393,7 +413,8 @@
     }
 
     @Opcode("CAS")
-    public static class CompareAndSwapOp extends AMD64LIRInstruction {
+    public static final class CompareAndSwapOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class);
 
         private final Kind accessKind;
 
@@ -403,6 +424,7 @@
         @Use protected AllocatableValue newValue;
 
         public CompareAndSwapOp(Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
+            super(TYPE);
             this.accessKind = accessKind;
             this.result = result;
             this.address = address;
@@ -432,7 +454,8 @@
     }
 
     @Opcode("ATOMIC_READ_AND_ADD")
-    public static class AtomicReadAndAddOp extends AMD64LIRInstruction {
+    public static final class AtomicReadAndAddOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<AtomicReadAndAddOp> TYPE = LIRInstructionClass.create(AtomicReadAndAddOp.class);
 
         private final Kind accessKind;
 
@@ -441,6 +464,7 @@
         @Use protected AllocatableValue delta;
 
         public AtomicReadAndAddOp(Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue delta) {
+            super(TYPE);
             this.accessKind = accessKind;
             this.result = result;
             this.address = address;
@@ -467,7 +491,8 @@
     }
 
     @Opcode("ATOMIC_READ_AND_WRITE")
-    public static class AtomicReadAndWriteOp extends AMD64LIRInstruction {
+    public static final class AtomicReadAndWriteOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<AtomicReadAndWriteOp> TYPE = LIRInstructionClass.create(AtomicReadAndWriteOp.class);
 
         private final Kind accessKind;
 
@@ -476,6 +501,7 @@
         @Use protected AllocatableValue newValue;
 
         public AtomicReadAndWriteOp(Kind accessKind, AllocatableValue result, AMD64AddressValue address, AllocatableValue newValue) {
+            super(TYPE);
             this.accessKind = accessKind;
             this.result = result;
             this.address = address;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
  */
 @Opcode("RESTORE_REGISTER")
 public class AMD64RestoreRegistersOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64RestoreRegistersOp> TYPE = LIRInstructionClass.create(AMD64RestoreRegistersOp.class);
 
     /**
      * The slots from which the registers are restored.
@@ -49,6 +50,11 @@
     private final AMD64SaveRegistersOp save;
 
     public AMD64RestoreRegistersOp(StackSlotValue[] values, AMD64SaveRegistersOp save) {
+        this(TYPE, values, save);
+    }
+
+    protected AMD64RestoreRegistersOp(LIRInstructionClass<? extends AMD64RestoreRegistersOp> c, StackSlotValue[] values, AMD64SaveRegistersOp save) {
+        super(c);
         assert Arrays.asList(values).stream().allMatch(ValueUtil::isVirtualStackSlot);
         this.slots = values;
         this.save = save;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
  */
 @Opcode("SAVE_REGISTER")
 public class AMD64SaveRegistersOp extends AMD64LIRInstruction implements SaveRegistersOp {
+    public static final LIRInstructionClass<AMD64SaveRegistersOp> TYPE = LIRInstructionClass.create(AMD64SaveRegistersOp.class);
 
     /**
      * The registers (potentially) saved by this operation.
@@ -63,6 +64,11 @@
      * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
      */
     public AMD64SaveRegistersOp(Register[] savedRegisters, StackSlotValue[] savedRegisterLocations, boolean supportsRemove) {
+        this(TYPE, savedRegisters, savedRegisterLocations, supportsRemove);
+    }
+
+    public AMD64SaveRegistersOp(LIRInstructionClass<? extends AMD64SaveRegistersOp> c, Register[] savedRegisters, StackSlotValue[] savedRegisterLocations, boolean supportsRemove) {
+        super(c);
         assert Arrays.asList(savedRegisterLocations).stream().allMatch(ValueUtil::isVirtualStackSlot);
         this.savedRegisters = savedRegisters;
         this.slots = savedRegisterLocations;
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -32,12 +32,13 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MemOp;
 import com.oracle.graal.lir.asm.*;
 
-public class AMD64TestMemoryOp extends MemOp {
+public final class AMD64TestMemoryOp extends MemOp {
+    public static final LIRInstructionClass<AMD64TestMemoryOp> TYPE = LIRInstructionClass.create(AMD64TestMemoryOp.class);
 
     @Use({REG, CONST}) protected Value y;
 
     public AMD64TestMemoryOp(Kind kind, AMD64AddressValue x, Value y, LIRFrameState state) {
-        super(kind, x, state);
+        super(TYPE, kind, x, state);
         this.y = y;
         this.state = state;
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -28,14 +28,17 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
-public class AMD64TestOp extends AMD64LIRInstruction {
+public final class AMD64TestOp extends AMD64LIRInstruction {
+    public static final LIRInstructionClass<AMD64TestOp> TYPE = LIRInstructionClass.create(AMD64TestOp.class);
 
     @Use({REG}) protected Value x;
     @Use({REG, STACK, CONST}) protected Value y;
 
     public AMD64TestOp(Value x, Value y) {
+        super(TYPE);
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,6 +40,7 @@
  */
 @Opcode("ZAP_REGISTER")
 public final class AMD64ZapRegistersOp extends AMD64LIRInstruction implements SaveRegistersOp {
+    public static final LIRInstructionClass<AMD64ZapRegistersOp> TYPE = LIRInstructionClass.create(AMD64ZapRegistersOp.class);
 
     /**
      * The registers that are zapped.
@@ -52,6 +53,7 @@
     @Use({CONST}) protected JavaConstant[] zapValues;
 
     public AMD64ZapRegistersOp(Register[] zappedRegisters, JavaConstant[] zapValues) {
+        super(TYPE);
         this.zappedRegisters = zappedRegisters;
         this.zapValues = zapValues;
     }
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,8 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 
-public class SPARCAddressValue extends CompositeValue {
+public final class SPARCAddressValue extends CompositeValue {
+    public static final CompositeValueClass<SPARCAddressValue> TYPE = CompositeValueClass.create(SPARCAddressValue.class);
 
     private static final long serialVersionUID = -3583286416638228207L;
 
@@ -44,7 +45,7 @@
     }
 
     public SPARCAddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index, int displacement) {
-        super(kind);
+        super(TYPE, kind);
         assert isIllegal(index) || displacement == 0;
         this.base = base;
         this.index = index;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Sat Feb 21 19:55:33 2015 +0100
@@ -56,13 +56,15 @@
     /**
      * Unary operation with separate source and destination operand.
      */
-    public static class Unary2Op extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final class Unary2Op extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<Unary2Op> TYPE = LIRInstructionClass.create(Unary2Op.class);
 
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
         @Use({REG}) protected AllocatableValue x;
 
         public Unary2Op(SPARCArithmetic opcode, AllocatableValue result, AllocatableValue x) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -78,7 +80,8 @@
      * Binary operation with two operands. The first source operand is combined with the
      * destination. The second source operand must be a register.
      */
-    public static class BinaryRegReg extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final class BinaryRegReg extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<BinaryRegReg> TYPE = LIRInstructionClass.create(BinaryRegReg.class);
 
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG, HINT}) protected Value result;
@@ -91,6 +94,7 @@
         }
 
         public BinaryRegReg(SPARCArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -113,7 +117,8 @@
     /**
      * Binary operation with single source/destination operand and one constant.
      */
-    public static class BinaryRegConst extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final class BinaryRegConst extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<BinaryRegConst> TYPE = LIRInstructionClass.create(BinaryRegConst.class);
 
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG, HINT}) protected AllocatableValue result;
@@ -126,6 +131,7 @@
         }
 
         public BinaryRegConst(SPARCArithmetic opcode, AllocatableValue result, Value x, JavaConstant y, LIRFrameState state) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -148,7 +154,8 @@
     /**
      * Special LIR instruction as it requires a bunch of scratch registers.
      */
-    public static class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final class RemOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<RemOp> TYPE = LIRInstructionClass.create(RemOp.class);
 
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG}) protected Value result;
@@ -159,6 +166,7 @@
         @State protected LIRFrameState state;
 
         public RemOp(SPARCArithmetic opcode, Value result, Value x, Value y, LIRFrameState state, LIRGeneratorTool gen) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -183,7 +191,8 @@
     /**
      * Calculates the product and condition code for long multiplication of long values.
      */
-    public static class SPARCLMulccOp extends SPARCLIRInstruction {
+    public static final class SPARCLMulccOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<SPARCLMulccOp> TYPE = LIRInstructionClass.create(SPARCLMulccOp.class);
         @Def({REG}) protected Value result;
         @Alive({REG}) protected Value x;
         @Alive({REG}) protected Value y;
@@ -191,6 +200,7 @@
         @Temp({REG}) protected Value scratch2;
 
         public SPARCLMulccOp(Value result, Value x, Value y, LIRGeneratorTool gen) {
+            super(TYPE);
             this.result = result;
             this.x = x;
             this.y = y;
@@ -835,7 +845,8 @@
         }
     }
 
-    public static class MulHighOp extends SPARCLIRInstruction {
+    public static final class MulHighOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<MulHighOp> TYPE = LIRInstructionClass.create(MulHighOp.class);
 
         @Opcode private final SPARCArithmetic opcode;
         @Def({REG}) public AllocatableValue result;
@@ -844,6 +855,7 @@
         @Temp({REG}) public AllocatableValue scratch;
 
         public MulHighOp(SPARCArithmetic opcode, AllocatableValue x, AllocatableValue y, AllocatableValue result, AllocatableValue scratch) {
+            super(TYPE);
             this.opcode = opcode;
             this.x = x;
             this.y = y;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,8 @@
  * Emits code which compares two arrays of the same length.
  */
 @Opcode("ARRAY_EQUALS")
-public class SPARCArrayEqualsOp extends SPARCLIRInstruction {
+public final class SPARCArrayEqualsOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCArrayEqualsOp> TYPE = LIRInstructionClass.create(SPARCArrayEqualsOp.class);
 
     private final Kind kind;
     private final int arrayBaseOffset;
@@ -63,6 +64,7 @@
     @Temp({REG}) protected Value temp5;
 
     public SPARCArrayEqualsOp(LIRGeneratorTool tool, Kind kind, Value result, Value array1, Value array2, Value length) {
+        super(TYPE);
         this.kind = kind;
 
         Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -41,7 +41,8 @@
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.gen.*;
 
-public class SPARCBitManipulationOp extends SPARCLIRInstruction {
+public final class SPARCBitManipulationOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCBitManipulationOp> TYPE = LIRInstructionClass.create(SPARCBitManipulationOp.class);
 
     public enum IntrinsicOpcode {
         IPOPCNT,
@@ -57,6 +58,7 @@
     @Temp({REG}) protected Value scratch;
 
     public SPARCBitManipulationOp(IntrinsicOpcode opcode, AllocatableValue result, AllocatableValue input, LIRGeneratorTool gen) {
+        super(TYPE);
         this.opcode = opcode;
         this.result = result;
         this.input = input;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBreakpointOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBreakpointOp.java	Sat Feb 21 19:55:33 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
@@ -34,7 +34,8 @@
  * Emits a breakpoint.
  */
 @Opcode("BREAKPOINT")
-public class SPARCBreakpointOp extends SPARCLIRInstruction {
+public final class SPARCBreakpointOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCBreakpointOp> TYPE = LIRInstructionClass.create(SPARCBreakpointOp.class);
 
     // historical - from hotspot src/cpu/sparc/vm
     // <sys/trap.h> promises that the system will not use traps 16-31
@@ -47,6 +48,7 @@
     @Use({REG, STACK}) protected Value[] parameters;
 
     public SPARCBreakpointOp(Value[] parameters) {
+        super(TYPE);
         this.parameters = parameters;
     }
 
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java	Sat Feb 21 19:55:33 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
@@ -35,7 +35,8 @@
 import com.oracle.graal.lir.gen.*;
 
 @Opcode("BSWAP")
-public class SPARCByteSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+public final class SPARCByteSwapOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCByteSwapOp> TYPE = LIRInstructionClass.create(SPARCByteSwapOp.class);
 
     @Def({REG, HINT}) protected Value result;
     @Use({REG}) protected Value input;
@@ -43,6 +44,7 @@
     @Use({STACK}) protected StackSlotValue tmpSlot;
 
     public SPARCByteSwapOp(LIRGeneratorTool tool, Value result, Value input) {
+        super(TYPE);
         this.result = result;
         this.input = input;
         this.tmpSlot = tool.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(Kind.Long));
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Sat Feb 21 19:55:33 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
@@ -41,13 +41,15 @@
 public class SPARCCall {
 
     public abstract static class CallOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CallOp> TYPE = LIRInstructionClass.create(CallOp.class);
 
         @Def({REG, ILLEGAL}) protected Value result;
         @Use({REG, STACK}) protected Value[] parameters;
         @Temp protected Value[] temps;
         @State protected LIRFrameState state;
 
-        public CallOp(Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+        protected CallOp(LIRInstructionClass<? extends CallOp> c, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c);
             this.result = result;
             this.parameters = parameters;
             this.state = state;
@@ -62,27 +64,32 @@
     }
 
     public abstract static class MethodCallOp extends CallOp {
+        public static final LIRInstructionClass<MethodCallOp> TYPE = LIRInstructionClass.create(MethodCallOp.class);
 
         protected final ResolvedJavaMethod callTarget;
 
-        public MethodCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(result, parameters, temps, state);
+        protected MethodCallOp(LIRInstructionClass<? extends MethodCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
             this.callTarget = callTarget;
         }
 
     }
 
     @Opcode("CALL_DIRECT")
-    public static class DirectCallOp extends MethodCallOp /* implements SPARCDelayedControlTransfer */{
+    public abstract static class DirectCallOp extends MethodCallOp /*
+                                                                    * implements
+                                                                    * SPARCDelayedControlTransfer
+                                                                    */{
+        public static final LIRInstructionClass<DirectCallOp> TYPE = LIRInstructionClass.create(DirectCallOp.class);
         private boolean emitted = false;
         private int before = -1;
 
-        public DirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+        public DirectCallOp(LIRInstructionClass<? extends DirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
         }
 
         @Override
-        public final void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
+        public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             if (!emitted) {
                 emitCallPrefixCode(crb, masm);
                 directCall(crb, masm, callTarget, null, true, state);
@@ -122,12 +129,14 @@
     }
 
     @Opcode("CALL_INDIRECT")
-    public static class IndirectCallOp extends MethodCallOp {
+    public abstract static class IndirectCallOp extends MethodCallOp {
+        public static final LIRInstructionClass<IndirectCallOp> TYPE = LIRInstructionClass.create(IndirectCallOp.class);
 
         @Use({REG}) protected Value targetAddress;
 
-        public IndirectCallOp(ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+        protected IndirectCallOp(LIRInstructionClass<? extends IndirectCallOp> c, ResolvedJavaMethod callTarget, Value result, Value[] parameters, Value[] temps, Value targetAddress,
+                        LIRFrameState state) {
+            super(c, callTarget, result, parameters, temps, state);
             this.targetAddress = targetAddress;
         }
 
@@ -144,11 +153,12 @@
     }
 
     public abstract static class ForeignCallOp extends CallOp {
+        public static final LIRInstructionClass<ForeignCallOp> TYPE = LIRInstructionClass.create(ForeignCallOp.class);
 
         protected final ForeignCallLinkage callTarget;
 
-        public ForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(result, parameters, temps, state);
+        public ForeignCallOp(LIRInstructionClass<? extends ForeignCallOp> c, ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
+            super(c, result, parameters, temps, state);
             this.callTarget = callTarget;
         }
 
@@ -159,10 +169,11 @@
     }
 
     @Opcode("NEAR_FOREIGN_CALL")
-    public static class DirectNearForeignCallOp extends ForeignCallOp {
+    public static final class DirectNearForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectNearForeignCallOp> TYPE = LIRInstructionClass.create(DirectNearForeignCallOp.class);
 
         public DirectNearForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(linkage, result, parameters, temps, state);
+            super(TYPE, linkage, result, parameters, temps, state);
         }
 
         @Override
@@ -172,10 +183,11 @@
     }
 
     @Opcode("FAR_FOREIGN_CALL")
-    public static class DirectFarForeignCallOp extends ForeignCallOp {
+    public static final class DirectFarForeignCallOp extends ForeignCallOp {
+        public static final LIRInstructionClass<DirectFarForeignCallOp> TYPE = LIRInstructionClass.create(DirectFarForeignCallOp.class);
 
         public DirectFarForeignCallOp(ForeignCallLinkage callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState state) {
-            super(callTarget, result, parameters, temps, state);
+            super(TYPE, callTarget, result, parameters, temps, state);
         }
 
         @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCompare.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCompare.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,13 +40,15 @@
     FCMP,
     DCMP;
 
-    public static class CompareOp extends SPARCLIRInstruction {
+    public static final class CompareOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CompareOp> TYPE = LIRInstructionClass.create(CompareOp.class);
 
         @Opcode private final SPARCCompare opcode;
         @Use({REG}) protected Value x;
         @Use({REG, CONST}) protected Value y;
 
         public CompareOp(SPARCCompare opcode, Value x, Value y) {
+            super(TYPE);
             this.opcode = opcode;
             this.x = x;
             this.y = y;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -42,11 +42,13 @@
 
 public class SPARCControlFlow {
 
-    public static class ReturnOp extends SPARCLIRInstruction implements BlockEndOp {
+    public static final class ReturnOp extends SPARCLIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<ReturnOp> TYPE = LIRInstructionClass.create(ReturnOp.class);
 
         @Use({REG, ILLEGAL}) protected Value x;
 
         public ReturnOp(Value x) {
+            super(TYPE);
             this.x = x;
         }
 
@@ -62,7 +64,8 @@
         }
     }
 
-    public static class CompareBranchOp extends SPARCLIRInstruction implements BlockEndOp, SPARCDelayedControlTransfer {
+    public static final class CompareBranchOp extends SPARCLIRInstruction implements BlockEndOp, SPARCDelayedControlTransfer {
+        public static final LIRInstructionClass<CompareBranchOp> TYPE = LIRInstructionClass.create(CompareBranchOp.class);
 
         private final SPARCCompare opcode;
         @Use({REG}) protected Value x;
@@ -83,6 +86,7 @@
 
         public CompareBranchOp(SPARCCompare opcode, Value x, Value y, Condition condition, LabelRef trueDestination, LabelRef falseDestination, Kind kind, boolean unorderedIsTrue,
                         double trueDestinationProbability) {
+            super(TYPE);
             this.opcode = opcode;
             this.x = x;
             this.y = y;
@@ -348,7 +352,8 @@
         }
     }
 
-    public static class BranchOp extends SPARCLIRInstruction implements StandardOp.BranchOp {
+    public static final class BranchOp extends SPARCLIRInstruction implements StandardOp.BranchOp {
+        public static final LIRInstructionClass<BranchOp> TYPE = LIRInstructionClass.create(BranchOp.class);
         // TODO: Condition code/flag handling needs to be improved;
         protected final Condition condition;
         protected final ConditionFlag conditionFlag;
@@ -358,6 +363,7 @@
         protected final boolean unorderedIsTrue;
 
         public BranchOp(ConditionFlag condition, LabelRef trueDestination, LabelRef falseDestination, Kind kind) {
+            super(TYPE);
             this.conditionFlag = condition;
             this.trueDestination = trueDestination;
             this.falseDestination = falseDestination;
@@ -367,6 +373,7 @@
         }
 
         public BranchOp(Condition condition, LabelRef trueDestination, LabelRef falseDestination, Kind kind) {
+            super(TYPE);
             this.condition = condition;
             this.trueDestination = trueDestination;
             this.falseDestination = falseDestination;
@@ -376,6 +383,7 @@
         }
 
         public BranchOp(Condition finalCondition, LabelRef trueDestination, LabelRef falseDestination, Kind kind, boolean unorderedIsTrue) {
+            super(TYPE);
             this.trueDestination = trueDestination;
             this.falseDestination = falseDestination;
             this.kind = kind;
@@ -517,7 +525,8 @@
         }
     }
 
-    public static class StrategySwitchOp extends SPARCLIRInstruction implements BlockEndOp {
+    public static final class StrategySwitchOp extends SPARCLIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<StrategySwitchOp> TYPE = LIRInstructionClass.create(StrategySwitchOp.class);
         @Use({CONST}) protected JavaConstant[] keyConstants;
         private final LabelRef[] keyTargets;
         private LabelRef defaultTarget;
@@ -526,6 +535,7 @@
         private final SwitchStrategy strategy;
 
         public StrategySwitchOp(SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Value key, Value scratch) {
+            super(TYPE);
             this.strategy = strategy;
             this.keyConstants = strategy.keyConstants;
             this.keyTargets = keyTargets;
@@ -583,7 +593,8 @@
         }
     }
 
-    public static class TableSwitchOp extends SPARCLIRInstruction implements BlockEndOp {
+    public static final class TableSwitchOp extends SPARCLIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<TableSwitchOp> TYPE = LIRInstructionClass.create(TableSwitchOp.class);
 
         private final int lowKey;
         private final LabelRef defaultTarget;
@@ -592,6 +603,7 @@
         @Temp protected Value scratch;
 
         public TableSwitchOp(final int lowKey, final LabelRef defaultTarget, final LabelRef[] targets, Variable index, Variable scratch) {
+            super(TYPE);
             this.lowKey = lowKey;
             this.defaultTarget = defaultTarget;
             this.targets = targets;
@@ -655,7 +667,8 @@
     }
 
     @Opcode("CMOVE")
-    public static class CondMoveOp extends SPARCLIRInstruction {
+    public static final class CondMoveOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
 
         private final Kind kind;
 
@@ -667,6 +680,7 @@
         private final CC cc;
 
         public CondMoveOp(Kind kind, Variable result, CC cc, ConditionFlag condition, Value trueValue, Value falseValue) {
+            super(TYPE);
             this.kind = kind;
             this.result = result;
             this.condition = condition;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,7 +35,7 @@
  *
  * <pre>
  *   Base       Contents
- * 
+ *
  *            :                                :  -----
  *   caller   | incoming overflow argument n   |    ^
  *   frame    :     ...                        :    | positive
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCJumpOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCJumpOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,12 +29,13 @@
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.asm.*;
 
-public class SPARCJumpOp extends JumpOp implements SPARCDelayedControlTransfer {
+public final class SPARCJumpOp extends JumpOp implements SPARCDelayedControlTransfer {
+    public static final LIRInstructionClass<SPARCJumpOp> TYPE = LIRInstructionClass.create(SPARCJumpOp.class);
     private boolean emitDone = false;
     private int delaySlotPosition = -1;
 
     public SPARCJumpOp(LabelRef destination) {
-        super(destination);
+        super(TYPE, destination);
     }
 
     public void emitControlTransfer(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLIRInstruction.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLIRInstruction.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -29,7 +29,13 @@
 /**
  * Convenience class to provide SPARCMacroAssembler for the {@link #emitCode} method.
  */
-public abstract class SPARCLIRInstruction extends LIRInstructionBase {
+public abstract class SPARCLIRInstruction extends LIRInstruction {
+    public static final LIRInstructionClass<SPARCLIRInstruction> TYPE = LIRInstructionClass.create(SPARCLIRInstruction.class);
+
+    protected SPARCLIRInstruction(LIRInstructionClass<? extends LIRInstruction> c) {
+        super(c);
+    }
+
     protected SPARCDelayedControlTransfer delayedControlTransfer = SPARCDelayedControlTransfer.DUMMY;
 
     @Override
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMathIntrinsicOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMathIntrinsicOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,7 +31,8 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
-public class SPARCMathIntrinsicOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+public final class SPARCMathIntrinsicOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final LIRInstructionClass<SPARCMathIntrinsicOp> TYPE = LIRInstructionClass.create(SPARCMathIntrinsicOp.class);
 
     public enum IntrinsicOpcode {
         SQRT,
@@ -48,6 +49,7 @@
     @Use protected Value input;
 
     public SPARCMathIntrinsicOp(IntrinsicOpcode opcode, Value result, Value input) {
+        super(TYPE);
         this.opcode = opcode;
         this.result = result;
         this.input = input;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -74,11 +74,13 @@
 
     @Opcode("MOVE_TOREG")
     public static class MoveToRegOp extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<MoveToRegOp> TYPE = LIRInstructionClass.create(MoveToRegOp.class);
 
         @Def({REG, HINT}) protected AllocatableValue result;
         @Use({REG, STACK, CONST}) protected Value input;
 
         public MoveToRegOp(AllocatableValue result, Value input) {
+            super(TYPE);
             this.result = result;
             this.input = input;
         }
@@ -100,12 +102,14 @@
     }
 
     @Opcode("MOVE_FROMREG")
-    public static class MoveFromRegOp extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+    public static final class MoveFromRegOp extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<MoveFromRegOp> TYPE = LIRInstructionClass.create(MoveFromRegOp.class);
 
         @Def({REG, STACK}) protected AllocatableValue result;
         @Use({REG, CONST, HINT}) protected Value input;
 
         public MoveFromRegOp(AllocatableValue result, Value input) {
+            super(TYPE);
             this.result = result;
             this.input = input;
         }
@@ -130,14 +134,15 @@
      * Move between floating-point and general purpose register domain (WITHOUT VIS3).
      */
     @Opcode("MOVE")
-    public static class MoveFpGp extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+    public static final class MoveFpGp extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<MoveFpGp> TYPE = LIRInstructionClass.create(MoveFpGp.class);
 
         @Def({REG}) protected AllocatableValue result;
         @Use({REG}) protected AllocatableValue input;
         @Use({STACK}) protected StackSlotValue temp;
 
         public MoveFpGp(AllocatableValue result, AllocatableValue input, StackSlotValue temp) {
-            super();
+            super(TYPE);
             this.result = result;
             this.input = input;
             this.temp = temp;
@@ -224,13 +229,14 @@
      * Move between floating-point and general purpose register domain (WITH VIS3).
      */
     @Opcode("MOVE")
-    public static class MoveFpGpVIS3 extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+    public static final class MoveFpGpVIS3 extends SPARCLIRInstruction implements MoveOp, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<MoveFpGpVIS3> TYPE = LIRInstructionClass.create(MoveFpGpVIS3.class);
 
         @Def({REG}) protected AllocatableValue result;
         @Use({REG}) protected AllocatableValue input;
 
         public MoveFpGpVIS3(AllocatableValue result, AllocatableValue input) {
-            super();
+            super(TYPE);
             this.result = result;
             this.input = input;
         }
@@ -277,12 +283,14 @@
     }
 
     public abstract static class MemOp extends SPARCLIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemOp> TYPE = LIRInstructionClass.create(MemOp.class);
 
         protected final Kind kind;
         @Use({COMPOSITE}) protected SPARCAddressValue address;
         @State protected LIRFrameState state;
 
-        public MemOp(Kind kind, SPARCAddressValue address, LIRFrameState state) {
+        public MemOp(LIRInstructionClass<? extends MemOp> c, Kind kind, SPARCAddressValue address, LIRFrameState state) {
+            super(c);
             this.kind = kind;
             this.address = address;
             this.state = state;
@@ -304,12 +312,13 @@
         }
     }
 
-    public static class LoadOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+    public static final class LoadOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<LoadOp> TYPE = LIRInstructionClass.create(LoadOp.class);
 
         @Def({REG}) protected AllocatableValue result;
 
         public LoadOp(Kind kind, AllocatableValue result, SPARCAddressValue address, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.result = result;
         }
 
@@ -356,12 +365,14 @@
         }
     }
 
-    public static class LoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final class LoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<LoadAddressOp> TYPE = LIRInstructionClass.create(LoadAddressOp.class);
 
         @Def({REG}) protected AllocatableValue result;
         @Use({COMPOSITE, UNINITIALIZED}) protected SPARCAddressValue addressValue;
 
         public LoadAddressOp(AllocatableValue result, SPARCAddressValue address) {
+            super(TYPE);
             this.result = result;
             this.addressValue = address;
         }
@@ -373,12 +384,14 @@
         }
     }
 
-    public static class LoadDataAddressOp extends SPARCLIRInstruction {
+    public static final class LoadDataAddressOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<LoadDataAddressOp> TYPE = LIRInstructionClass.create(LoadDataAddressOp.class);
 
         @Def({REG}) protected AllocatableValue result;
         private final byte[] data;
 
         public LoadDataAddressOp(AllocatableValue result, byte[] data) {
+            super(TYPE);
             this.result = result;
             this.data = data;
         }
@@ -393,11 +406,13 @@
         }
     }
 
-    public static class MembarOp extends SPARCLIRInstruction {
+    public static final class MembarOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
 
         private final int barriers;
 
         public MembarOp(final int barriers) {
+            super(TYPE);
             this.barriers = barriers;
         }
 
@@ -407,12 +422,14 @@
         }
     }
 
-    public static class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction {
+    public static final class NullCheckOp extends SPARCLIRInstruction implements NullCheck, SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<NullCheckOp> TYPE = LIRInstructionClass.create(NullCheckOp.class);
 
         @Use({REG}) protected AllocatableValue input;
         @State protected LIRFrameState state;
 
         public NullCheckOp(Variable input, LIRFrameState state) {
+            super(TYPE);
             this.input = input;
             this.state = state;
         }
@@ -434,7 +451,8 @@
     }
 
     @Opcode("CAS")
-    public static class CompareAndSwapOp extends SPARCLIRInstruction {
+    public static final class CompareAndSwapOp extends SPARCLIRInstruction {
+        public static final LIRInstructionClass<CompareAndSwapOp> TYPE = LIRInstructionClass.create(CompareAndSwapOp.class);
 
         @Def({REG, HINT}) protected AllocatableValue result;
         @Alive({REG}) protected AllocatableValue address;
@@ -442,6 +460,7 @@
         @Use({REG}) protected AllocatableValue newValue;
 
         public CompareAndSwapOp(AllocatableValue result, AllocatableValue address, AllocatableValue cmpValue, AllocatableValue newValue) {
+            super(TYPE);
             this.result = result;
             this.address = address;
             this.cmpValue = cmpValue;
@@ -455,12 +474,14 @@
         }
     }
 
-    public static class StackLoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+    public static final class StackLoadAddressOp extends SPARCLIRInstruction implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<StackLoadAddressOp> TYPE = LIRInstructionClass.create(StackLoadAddressOp.class);
 
         @Def({REG}) protected AllocatableValue result;
         @Use({STACK, UNINITIALIZED}) protected StackSlotValue slot;
 
         public StackLoadAddressOp(AllocatableValue result, StackSlotValue address) {
+            super(TYPE);
             this.result = result;
             this.slot = address;
         }
@@ -491,11 +512,12 @@
     }
 
     public static class StoreOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<StoreOp> TYPE = LIRInstructionClass.create(StoreOp.class);
 
         @Use({REG}) protected AllocatableValue input;
 
         public StoreOp(Kind kind, SPARCAddressValue address, AllocatableValue input, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.input = input;
         }
 
@@ -540,12 +562,13 @@
         }
     }
 
-    public static class StoreConstantOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+    public static final class StoreConstantOp extends MemOp implements SPARCTailDelayedLIRInstruction {
+        public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class);
 
         protected final JavaConstant input;
 
         public StoreConstantOp(Kind kind, SPARCAddressValue address, JavaConstant input, LIRFrameState state) {
-            super(kind, address, state);
+            super(TYPE, kind, address, state);
             this.input = input;
             if (!input.isDefaultForKind()) {
                 throw GraalInternalError.shouldNotReachHere("Can only store null constants to memory");
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Sat Feb 21 19:55:33 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
@@ -42,6 +42,7 @@
  */
 @Opcode("SAVE_REGISTER")
 public class SPARCSaveRegistersOp extends SPARCLIRInstruction implements SaveRegistersOp {
+    public static final LIRInstructionClass<SPARCSaveRegistersOp> TYPE = LIRInstructionClass.create(SPARCSaveRegistersOp.class);
     public static final Register RETURN_REGISTER_STORAGE = SPARC.d62;
     /**
      * The registers (potentially) saved by this operation.
@@ -66,6 +67,7 @@
      * @param supportsRemove determines if registers can be {@linkplain #remove(Set) pruned}
      */
     public SPARCSaveRegistersOp(Register[] savedRegisters, StackSlotValue[] savedRegisterLocations, boolean supportsRemove) {
+        super(TYPE);
         assert Arrays.asList(savedRegisterLocations).stream().allMatch(ValueUtil::isVirtualStackSlot);
         this.savedRegisters = savedRegisters;
         this.slots = savedRegisterLocations;
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -30,14 +30,17 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
 public class SPARCTestOp extends SPARCLIRInstruction {
+    public static final LIRInstructionClass<SPARCTestOp> TYPE = LIRInstructionClass.create(SPARCTestOp.class);
 
     @Use({REG}) protected Value x;
     @Use({REG, CONST}) protected Value y;
 
     public SPARCTestOp(Value x, Value y) {
+        super(TYPE);
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -39,12 +39,13 @@
 public class CompositeValueReplacementTest1 {
 
     private static class NestedCompositeValue extends CompositeValue {
+        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
 
         private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
 
         public NestedCompositeValue(Value value) {
-            super(LIRKind.Illegal);
+            super(TYPE, LIRKind.Illegal);
             this.value = value;
         }
 
@@ -94,11 +95,13 @@
 
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static final class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected NestedCompositeValue compValue;
 
         public TestOp(NestedCompositeValue compValue) {
+            super(TYPE);
             this.compValue = compValue;
         }
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,12 +40,13 @@
 public class CompositeValueReplacementTest2 {
 
     private static class NestedCompositeValue extends CompositeValue {
+        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
 
         private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value[] values;
 
         public NestedCompositeValue(Value value) {
-            super(LIRKind.Illegal);
+            super(TYPE, LIRKind.Illegal);
             this.values = new Value[]{value};
         }
 
@@ -95,11 +96,13 @@
 
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static final class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected NestedCompositeValue compValue;
 
         public TestOp(NestedCompositeValue compValue) {
+            super(TYPE);
             this.compValue = compValue;
         }
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,12 +40,13 @@
 public class CompositeValueReplacementTest3 {
 
     private static class NestedCompositeValue extends CompositeValue {
+        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
 
         private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
 
         public NestedCompositeValue(Value value) {
-            super(LIRKind.Illegal);
+            super(TYPE, LIRKind.Illegal);
             this.value = value;
         }
 
@@ -95,11 +96,13 @@
 
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static final class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected NestedCompositeValue compValue;
 
         public TestOp(NestedCompositeValue compValue) {
+            super(TYPE);
             this.compValue = compValue;
         }
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,12 +40,13 @@
 public class CompositeValueReplacementTest4 {
 
     private static class NestedCompositeValue extends CompositeValue {
+        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
 
         private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value[] values;
 
         public NestedCompositeValue(Value value) {
-            super(LIRKind.Illegal);
+            super(TYPE, LIRKind.Illegal);
             this.values = new Value[]{value};
         }
 
@@ -95,11 +96,13 @@
 
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected NestedCompositeValue compValue;
 
         public TestOp(NestedCompositeValue compValue) {
+            super(TYPE);
             this.compValue = compValue;
         }
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -37,12 +37,13 @@
 public class ValuePositionTest1 {
 
     private static class NestedCompositeValue extends CompositeValue {
+        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
 
         private static final long serialVersionUID = -8804214200173503527L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value;
 
         public NestedCompositeValue(Value value) {
-            super(LIRKind.Illegal);
+            super(TYPE, LIRKind.Illegal);
             this.value = value;
         }
 
@@ -86,11 +87,13 @@
         }
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static final class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected NestedCompositeValue compValue;
 
         public TestOp(NestedCompositeValue compValue) {
+            super(TYPE);
             this.compValue = compValue;
         }
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -37,13 +37,14 @@
 public class ValuePositionTest2 {
 
     private static class NestedCompositeValue extends CompositeValue {
+        public static final CompositeValueClass<NestedCompositeValue> TYPE = CompositeValueClass.create(NestedCompositeValue.class);
 
         private static final long serialVersionUID = -2243948303328857965L;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value1;
         @Component({REG, OperandFlag.ILLEGAL}) protected Value value2;
 
         public NestedCompositeValue(Value value1, Value value2) {
-            super(LIRKind.Illegal);
+            super(TYPE, LIRKind.Illegal);
             this.value1 = value1;
             this.value2 = value2;
         }
@@ -88,11 +89,13 @@
         }
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected NestedCompositeValue compValue;
 
         public TestOp(NestedCompositeValue compValue) {
+            super(TYPE);
             this.compValue = compValue;
         }
 
--- a/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -38,6 +38,7 @@
 public class ValuePositionTest3 {
 
     public static final class TestAddressValue extends CompositeValue {
+        public static final CompositeValueClass<TestAddressValue> TYPE = CompositeValueClass.create(TestAddressValue.class);
 
         private static final long serialVersionUID = -2679790860680123026L;
 
@@ -49,7 +50,7 @@
         }
 
         public TestAddressValue(LIRKind kind, AllocatableValue base, AllocatableValue index) {
-            super(kind);
+            super(TYPE, kind);
             this.base = base;
             this.index = index;
         }
@@ -99,11 +100,13 @@
 
     }
 
-    private static class TestOp extends LIRInstructionBase {
+    private static class TestOp extends LIRInstruction {
+        public static final LIRInstructionClass<TestOp> TYPE = LIRInstructionClass.create(TestOp.class);
 
         @Use({COMPOSITE}) protected Value value;
 
         public TestOp(Value value) {
+            super(TYPE);
             this.value = value;
         }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Sat Feb 21 19:55:33 2015 +0100
@@ -44,14 +44,15 @@
         OperandFlag[] value() default OperandFlag.REG;
     }
 
-    private final CompositeValueClass valueClass;
+    private final CompositeValueClass<?> valueClass;
 
     private static final DebugMetric COMPOSITE_VALUE_COUNT = Debug.metric("CompositeValues");
 
-    public CompositeValue(LIRKind kind) {
+    public CompositeValue(CompositeValueClass<? extends CompositeValue> c, LIRKind kind) {
         super(kind);
         COMPOSITE_VALUE_COUNT.increment();
-        valueClass = CompositeValueClass.get(getClass());
+        valueClass = c;
+        assert c.getClazz() == this.getClass();
     }
 
     final CompositeValue forEachComponent(LIRInstruction inst, OperandMode mode, InstructionValueProcedure proc) {
@@ -81,7 +82,7 @@
         return false;
     }
 
-    CompositeValueClass getValueClass() {
+    CompositeValueClass<?> getValueClass() {
         return valueClass;
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,30 +38,17 @@
  * such fields.</li>
  * </ul>
  */
-public class CompositeValueClass extends LIRIntrospection {
-
-    public static final CompositeValueClass get(Class<? extends CompositeValue> c) {
-        CompositeValueClass clazz = (CompositeValueClass) allClasses.get(c);
-        if (clazz != null) {
-            return clazz;
-        }
+public class CompositeValueClass<T> extends LIRIntrospection<T> {
 
-        // We can have a race of multiple threads creating the LIRInstructionClass at the same time.
-        // However, only one will be put into the map, and this is the one returned by all threads.
-        clazz = new CompositeValueClass(c);
-        CompositeValueClass oldClazz = (CompositeValueClass) allClasses.putIfAbsent(c, clazz);
-        if (oldClazz != null) {
-            return oldClazz;
-        } else {
-            return clazz;
-        }
+    public static final <T extends CompositeValue> CompositeValueClass<T> create(Class<T> c) {
+        return new CompositeValueClass<>(c);
     }
 
-    public CompositeValueClass(Class<? extends CompositeValue> clazz) {
+    public CompositeValueClass(Class<T> clazz) {
         this(clazz, new FieldsScanner.DefaultCalcOffset());
     }
 
-    public CompositeValueClass(Class<? extends CompositeValue> clazz, FieldsScanner.CalcOffset calcOffset) {
+    public CompositeValueClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) {
         super(clazz);
 
         CompositeValueFieldsScanner vfs = new CompositeValueFieldsScanner(calcOffset);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,87 +26,98 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
 /**
  * This class performs basic optimizations on the control flow graph after LIR generation.
  */
-public final class ControlFlowOptimizer {
+public final class ControlFlowOptimizer extends PostAllocationOptimizationPhase {
 
     /**
      * Performs control flow optimizations on the given LIR graph.
      */
-    public static <T extends AbstractBlock<T>> void optimize(LIR lir, List<T> codeEmittingOrder) {
-        ControlFlowOptimizer.deleteEmptyBlocks(lir, codeEmittingOrder);
-    }
-
-    private ControlFlowOptimizer() {
-    }
-
-    private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted");
-
-    /**
-     * Checks whether a block can be deleted. Only blocks with exactly one successor and an
-     * unconditional branch to this successor are eligable.
-     *
-     * @param block the block checked for deletion
-     * @return whether the block can be deleted
-     */
-    private static boolean canDeleteBlock(LIR lir, AbstractBlock<?> block) {
-        if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors().iterator().next() == block) {
-            return false;
-        }
-
-        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-
-        assert instructions.size() >= 2 : "block must have label and branch";
-        assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
-        assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch";
-        assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors().iterator().next()).get(0)).getLabel() : "branch target must be the successor";
-
-        // Block must have exactly one successor.
-        return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry();
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        LIR lir = lirGenRes.getLIR();
+        new Optimizer<B>(lir).deleteEmptyBlocks(codeEmittingOrder);
     }
 
-    private static void alignBlock(LIR lir, AbstractBlock<?> block) {
-        if (!block.isAligned()) {
-            block.setAlign(true);
+    private static final class Optimizer<B extends AbstractBlock<B>> {
+
+        private final LIR lir;
+
+        private Optimizer(LIR lir) {
+            this.lir = lir;
+        }
+
+        private static final DebugMetric BLOCKS_DELETED = Debug.metric("BlocksDeleted");
+
+        /**
+         * Checks whether a block can be deleted. Only blocks with exactly one successor and an
+         * unconditional branch to this successor are eligable.
+         *
+         * @param block the block checked for deletion
+         * @return whether the block can be deleted
+         */
+        private boolean canDeleteBlock(B block) {
+            if (block.getSuccessorCount() != 1 || block.getPredecessorCount() == 0 || block.getSuccessors().iterator().next() == block) {
+                return false;
+            }
+
             List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+            assert instructions.size() >= 2 : "block must have label and branch";
             assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
-            StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0);
-            instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true));
+            assert instructions.get(instructions.size() - 1) instanceof StandardOp.JumpOp : "last instruction must always be a branch";
+            assert ((StandardOp.JumpOp) instructions.get(instructions.size() - 1)).destination().label() == ((StandardOp.LabelOp) lir.getLIRforBlock(block.getSuccessors().iterator().next()).get(0)).getLabel() : "branch target must be the successor";
+
+            // Block must have exactly one successor.
+            return instructions.size() == 2 && !instructions.get(instructions.size() - 1).hasState() && !block.isExceptionEntry();
+        }
+
+        private void alignBlock(B block) {
+            if (!block.isAligned()) {
+                block.setAlign(true);
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                assert instructions.get(0) instanceof StandardOp.LabelOp : "first instruction must always be a label";
+                StandardOp.LabelOp label = (StandardOp.LabelOp) instructions.get(0);
+                instructions.set(0, new StandardOp.LabelOp(label.getLabel(), true));
+            }
+        }
+
+        private void deleteEmptyBlocks(List<B> blocks) {
+            assert verifyBlocks(lir, blocks);
+            Iterator<B> iterator = blocks.iterator();
+            while (iterator.hasNext()) {
+                B block = iterator.next();
+                if (canDeleteBlock(block)) {
+                    // adjust successor and predecessor lists
+                    B other = block.getSuccessors().iterator().next();
+                    for (AbstractBlock<B> pred : block.getPredecessors()) {
+                        Collections.replaceAll(pred.getSuccessors(), block, other);
+                    }
+                    for (int i = 0; i < other.getPredecessorCount(); i++) {
+                        if (other.getPredecessors().get(i) == block) {
+                            other.getPredecessors().remove(i);
+                            other.getPredecessors().addAll(i, block.getPredecessors());
+                        }
+                    }
+                    block.getSuccessors().clear();
+                    block.getPredecessors().clear();
+
+                    if (block.isAligned()) {
+                        alignBlock(other);
+                    }
+
+                    BLOCKS_DELETED.increment();
+                    iterator.remove();
+                }
+            }
+            assert verifyBlocks(lir, blocks);
         }
     }
-
-    private static <T extends AbstractBlock<T>> void deleteEmptyBlocks(LIR lir, List<T> blocks) {
-        assert verifyBlocks(lir, blocks);
-        Iterator<T> iterator = blocks.iterator();
-        while (iterator.hasNext()) {
-            T block = iterator.next();
-            if (canDeleteBlock(lir, block)) {
-                // adjust successor and predecessor lists
-                T other = block.getSuccessors().iterator().next();
-                for (AbstractBlock<T> pred : block.getPredecessors()) {
-                    Collections.replaceAll(pred.getSuccessors(), block, other);
-                }
-                for (int i = 0; i < other.getPredecessorCount(); i++) {
-                    if (other.getPredecessors().get(i) == block) {
-                        other.getPredecessors().remove(i);
-                        other.getPredecessors().addAll(i, block.getPredecessors());
-                    }
-                }
-                block.getSuccessors().clear();
-                block.getPredecessors().clear();
-
-                if (block.isAligned()) {
-                    alignBlock(lir, other);
-                }
-
-                BLOCKS_DELETED.increment();
-                iterator.remove();
-            }
-        }
-        assert verifyBlocks(lir, blocks);
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,34 +24,36 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.MoveOp;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
 /**
  * This class optimizes moves, particularly those that result from eliminating SSA form.
- *
+ * <p>
  * When a block has more than one predecessor, and all predecessors end with the
- * {@linkplain #same(LIRInstruction, LIRInstruction) same} sequence of {@linkplain MoveOp move}
- * instructions, then these sequences can be replaced with a single copy of the sequence at the
- * beginning of the block.
- *
+ * {@linkplain Optimizer#same(LIRInstruction, LIRInstruction) same} sequence of {@linkplain MoveOp
+ * move} instructions, then these sequences can be replaced with a single copy of the sequence at
+ * the beginning of the block.
+ * <p>
  * Similarly, when a block has more than one successor, then same sequences of moves at the
  * beginning of the successors can be placed once at the end of the block. But because the moves
  * must be inserted before all branch instructions, this works only when there is exactly one
  * conditional branch at the end of the block (because the moves must be inserted before all
  * branches, but after all compares).
- *
+ * <p>
  * This optimization affects all kind of moves (reg-&gt;reg, reg-&gt;stack and stack-&gt;reg).
  * 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 {
+public final class EdgeMoveOptimizer extends PostAllocationOptimizationPhase {
 
-    /**
-     * Optimizes moves on block edges.
-     */
-    public static void optimize(LIR ir) {
-        EdgeMoveOptimizer optimizer = new EdgeMoveOptimizer(ir);
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        LIR ir = lirGenRes.getLIR();
+        Optimizer optimizer = new Optimizer(ir);
 
         List<? extends AbstractBlock<?>> blockList = ir.linearScanOrder();
         // ignore the first block in the list (index 0 is not processed)
@@ -67,213 +69,216 @@
         }
     }
 
-    private final List<List<LIRInstruction>> edgeInstructionSeqences;
-    private LIR ir;
-
-    public EdgeMoveOptimizer(LIR ir) {
-        this.ir = ir;
-        edgeInstructionSeqences = new ArrayList<>(4);
-    }
-
-    /**
-     * Determines if two operations are both {@linkplain MoveOp moves} that have the same
-     * {@linkplain MoveOp#getInput() source} and {@linkplain MoveOp#getResult() destination}
-     * operands.
-     *
-     * @param op1 the first instruction to compare
-     * @param op2 the second instruction to compare
-     * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm
-     */
-    private static boolean same(LIRInstruction op1, LIRInstruction op2) {
-        assert op1 != null;
-        assert op2 != null;
+    private static final class Optimizer {
+        private final List<List<LIRInstruction>> edgeInstructionSeqences;
+        private LIR ir;
 
-        if (op1 instanceof MoveOp && op2 instanceof MoveOp) {
-            MoveOp move1 = (MoveOp) op1;
-            MoveOp move2 = (MoveOp) op2;
-            if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
-                // these moves are exactly equal and can be optimized
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of
-     * {@code block} to the start of {@code block}.
-     */
-    private void optimizeMovesAtBlockEnd(AbstractBlock<?> block) {
-        for (AbstractBlock<?> pred : block.getPredecessors()) {
-            if (pred == block) {
-                // currently we can't handle this correctly.
-                return;
-            }
+        public Optimizer(LIR ir) {
+            this.ir = ir;
+            edgeInstructionSeqences = new ArrayList<>(4);
         }
 
-        // clear all internal data structures
-        edgeInstructionSeqences.clear();
-
-        int numPreds = block.getPredecessorCount();
-        assert numPreds > 1 : "do not call otherwise";
-
-        // setup a list with the LIR instructions of all predecessors
-        for (AbstractBlock<?> pred : block.getPredecessors()) {
-            assert pred != null;
-            assert ir.getLIRforBlock(pred) != null;
-            List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
+        /**
+         * Determines if two operations are both {@linkplain MoveOp moves} that have the same
+         * {@linkplain MoveOp#getInput() source} and {@linkplain MoveOp#getResult() destination}
+         * operands.
+         *
+         * @param op1 the first instruction to compare
+         * @param op2 the second instruction to compare
+         * @return {@code true} if {@code op1} and {@code op2} are the same by the above algorithm
+         */
+        private static boolean same(LIRInstruction op1, LIRInstruction op2) {
+            assert op1 != null;
+            assert op2 != null;
 
-            if (pred.getSuccessorCount() != 1) {
-                // this can happen with switch-statements where multiple edges are between
-                // the same blocks.
-                return;
+            if (op1 instanceof MoveOp && op2 instanceof MoveOp) {
+                MoveOp move1 = (MoveOp) op1;
+                MoveOp move2 = (MoveOp) op2;
+                if (move1.getInput().equals(move2.getInput()) && move1.getResult().equals(move2.getResult())) {
+                    // these moves are exactly equal and can be optimized
+                    return true;
+                }
             }
-
-            assert pred.getSuccessors().iterator().next() == block : "invalid control flow";
-            assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
-
-            if (predInstructions.get(predInstructions.size() - 1).hasState()) {
-                // can not optimize instructions that have debug info
-                return;
-            }
-
-            // ignore the unconditional branch at the end of the block
-            List<LIRInstruction> seq = predInstructions.subList(0, predInstructions.size() - 1);
-            edgeInstructionSeqences.add(seq);
+            return false;
         }
 
-        // process lir-instructions while all predecessors end with the same instruction
-        while (true) {
-            List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
-            if (seq.isEmpty()) {
-                return;
-            }
-
-            LIRInstruction op = last(seq);
-            for (int i = 1; i < numPreds; ++i) {
-                List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
-                if (otherSeq.isEmpty() || !same(op, last(otherSeq))) {
+        /**
+         * Moves the longest {@linkplain #same common} subsequence at the end all predecessors of
+         * {@code block} to the start of {@code block}.
+         */
+        private void optimizeMovesAtBlockEnd(AbstractBlock<?> block) {
+            for (AbstractBlock<?> pred : block.getPredecessors()) {
+                if (pred == block) {
+                    // currently we can't handle this correctly.
                     return;
                 }
             }
 
-            // insert the instruction at the beginning of the current block
-            ir.getLIRforBlock(block).add(1, op);
+            // clear all internal data structures
+            edgeInstructionSeqences.clear();
+
+            int numPreds = block.getPredecessorCount();
+            assert numPreds > 1 : "do not call otherwise";
+
+            // setup a list with the LIR instructions of all predecessors
+            for (AbstractBlock<?> pred : block.getPredecessors()) {
+                assert pred != null;
+                assert ir.getLIRforBlock(pred) != null;
+                List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
 
-            // delete the instruction at the end of all predecessors
-            for (int i = 0; i < numPreds; i++) {
-                seq = edgeInstructionSeqences.get(i);
-                removeLast(seq);
-            }
-        }
-    }
+                if (pred.getSuccessorCount() != 1) {
+                    // this can happen with switch-statements where multiple edges are between
+                    // the same blocks.
+                    return;
+                }
+
+                assert pred.getSuccessors().iterator().next() == block : "invalid control flow";
+                assert predInstructions.get(predInstructions.size() - 1) instanceof StandardOp.JumpOp : "block must end with unconditional jump";
+
+                if (predInstructions.get(predInstructions.size() - 1).hasState()) {
+                    // can not optimize instructions that have debug info
+                    return;
+                }
 
-    /**
-     * Moves the longest {@linkplain #same common} subsequence at the start of all successors of
-     * {@code block} to the end of {@code block} just prior to the branch instruction ending
-     * {@code block}.
-     */
-    private void optimizeMovesAtBlockBegin(AbstractBlock<?> block) {
+                // ignore the unconditional branch at the end of the block
+                List<LIRInstruction> seq = predInstructions.subList(0, predInstructions.size() - 1);
+                edgeInstructionSeqences.add(seq);
+            }
+
+            // process lir-instructions while all predecessors end with the same instruction
+            while (true) {
+                List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
+                if (seq.isEmpty()) {
+                    return;
+                }
 
-        edgeInstructionSeqences.clear();
-        int numSux = block.getSuccessorCount();
-
-        List<LIRInstruction> instructions = ir.getLIRforBlock(block);
+                LIRInstruction op = last(seq);
+                for (int i = 1; i < numPreds; ++i) {
+                    List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
+                    if (otherSeq.isEmpty() || !same(op, last(otherSeq))) {
+                        return;
+                    }
+                }
 
-        assert numSux == 2 : "method should not be called otherwise";
+                // insert the instruction at the beginning of the current block
+                ir.getLIRforBlock(block).add(1, op);
 
-        LIRInstruction lastInstruction = instructions.get(instructions.size() - 1);
-        if (lastInstruction.hasState()) {
-            // cannot optimize instructions when debug info is needed
-            return;
+                // delete the instruction at the end of all predecessors
+                for (int i = 0; i < numPreds; i++) {
+                    seq = edgeInstructionSeqences.get(i);
+                    removeLast(seq);
+                }
+            }
         }
 
-        LIRInstruction branch = lastInstruction;
-        if (!(branch instanceof StandardOp.BranchOp) || branch.hasOperands()) {
-            // Only blocks that end with a conditional branch are optimized.
-            // In addition, a conditional branch with operands (including state) cannot
-            // be optimized. Moving a successor instruction before such a branch may
-            // interfere with the operands of the branch. For example, a successive move
-            // instruction may redefine an input operand of the branch.
-            return;
-        }
-
-        // Now it is guaranteed that the block ends with a conditional branch.
-        // The instructions are inserted at the end of the block before the branch.
-        int insertIdx = instructions.size() - 1;
-
-        // setup a list with the lir-instructions of all successors
-        for (AbstractBlock<?> sux : block.getSuccessors()) {
-            List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
+        /**
+         * Moves the longest {@linkplain #same common} subsequence at the start of all successors of
+         * {@code block} to the end of {@code block} just prior to the branch instruction ending
+         * {@code block}.
+         */
+        private void optimizeMovesAtBlockBegin(AbstractBlock<?> block) {
 
-            assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
+            edgeInstructionSeqences.clear();
+            int numSux = block.getSuccessorCount();
 
-            if (sux.getPredecessorCount() != 1) {
-                // this can happen with switch-statements where multiple edges are between
-                // the same blocks.
-                return;
-            }
-            assert sux.getPredecessors().iterator().next() == block : "invalid control flow";
+            List<LIRInstruction> instructions = ir.getLIRforBlock(block);
 
-            // ignore the label at the beginning of the block
-            List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
-            edgeInstructionSeqences.add(seq);
-        }
+            assert numSux == 2 : "method should not be called otherwise";
 
-        // process LIR instructions while all successors begin with the same instruction
-        while (true) {
-            List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
-            if (seq.isEmpty()) {
+            LIRInstruction lastInstruction = instructions.get(instructions.size() - 1);
+            if (lastInstruction.hasState()) {
+                // cannot optimize instructions when debug info is needed
                 return;
             }
 
-            LIRInstruction op = first(seq);
-            for (int i = 1; i < numSux; i++) {
-                List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
-                if (otherSeq.isEmpty() || !same(op, first(otherSeq))) {
-                    // these instructions are different and cannot be optimized .
-                    // no further optimization possible
+            LIRInstruction branch = lastInstruction;
+            if (!(branch instanceof StandardOp.BranchOp) || branch.hasOperands()) {
+                // Only blocks that end with a conditional branch are optimized.
+                // In addition, a conditional branch with operands (including state) cannot
+                // be optimized. Moving a successor instruction before such a branch may
+                // interfere with the operands of the branch. For example, a successive move
+                // instruction may redefine an input operand of the branch.
+                return;
+            }
+
+            // Now it is guaranteed that the block ends with a conditional branch.
+            // The instructions are inserted at the end of the block before the branch.
+            int insertIdx = instructions.size() - 1;
+
+            // setup a list with the lir-instructions of all successors
+            for (AbstractBlock<?> sux : block.getSuccessors()) {
+                List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
+
+                assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
+
+                if (sux.getPredecessorCount() != 1) {
+                    // this can happen with switch-statements where multiple edges are between
+                    // the same blocks.
                     return;
                 }
+                assert sux.getPredecessors().iterator().next() == block : "invalid control flow";
+
+                // ignore the label at the beginning of the block
+                List<LIRInstruction> seq = suxInstructions.subList(1, suxInstructions.size());
+                edgeInstructionSeqences.add(seq);
             }
 
-            // insert instruction at end of current block
-            ir.getLIRforBlock(block).add(insertIdx, op);
-            insertIdx++;
+            // process LIR instructions while all successors begin with the same instruction
+            while (true) {
+                List<LIRInstruction> seq = edgeInstructionSeqences.get(0);
+                if (seq.isEmpty()) {
+                    return;
+                }
 
-            // delete the instructions at the beginning of all successors
-            for (int i = 0; i < numSux; i++) {
-                seq = edgeInstructionSeqences.get(i);
-                removeFirst(seq);
+                LIRInstruction op = first(seq);
+                for (int i = 1; i < numSux; i++) {
+                    List<LIRInstruction> otherSeq = edgeInstructionSeqences.get(i);
+                    if (otherSeq.isEmpty() || !same(op, first(otherSeq))) {
+                        // these instructions are different and cannot be optimized .
+                        // no further optimization possible
+                        return;
+                    }
+                }
+
+                // insert instruction at end of current block
+                ir.getLIRforBlock(block).add(insertIdx, op);
+                insertIdx++;
+
+                // delete the instructions at the beginning of all successors
+                for (int i = 0; i < numSux; i++) {
+                    seq = edgeInstructionSeqences.get(i);
+                    removeFirst(seq);
+                }
             }
         }
-    }
 
-    /**
-     * Gets the first element from a LIR instruction sequence.
-     */
-    private static LIRInstruction first(List<LIRInstruction> seq) {
-        return seq.get(0);
-    }
+        /**
+         * Gets the first element from a LIR instruction sequence.
+         */
+        private static LIRInstruction first(List<LIRInstruction> seq) {
+            return seq.get(0);
+        }
+
+        /**
+         * Gets the last element from a LIR instruction sequence.
+         */
+        private static LIRInstruction last(List<LIRInstruction> seq) {
+            return seq.get(seq.size() - 1);
+        }
 
-    /**
-     * Gets the last element from a LIR instruction sequence.
-     */
-    private static LIRInstruction last(List<LIRInstruction> seq) {
-        return seq.get(seq.size() - 1);
-    }
+        /**
+         * Removes the first element from a LIR instruction sequence.
+         */
+        private static void removeFirst(List<LIRInstruction> seq) {
+            seq.remove(0);
+        }
 
-    /**
-     * Removes the first element from a LIR instruction sequence.
-     */
-    private static void removeFirst(List<LIRInstruction> seq) {
-        seq.remove(0);
-    }
+        /**
+         * Removes the last element from a LIR instruction sequence.
+         */
+        private static void removeLast(List<LIRInstruction> seq) {
+            seq.remove(seq.size() - 1);
+        }
 
-    /**
-     * Removes the last element from a LIR instruction sequence.
-     */
-    private static void removeLast(List<LIRInstruction> seq) {
-        seq.remove(seq.size() - 1);
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FullInfopointOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FullInfopointOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,13 +29,15 @@
  * Emits an infopoint (only mark the position).
  */
 @Opcode("INFOPOINT")
-public class FullInfopointOp extends LIRInstructionBase {
+public final class FullInfopointOp extends LIRInstruction {
+    public static final LIRInstructionClass<FullInfopointOp> TYPE = LIRInstructionClass.create(FullInfopointOp.class);
 
     @State protected LIRFrameState state;
 
     private final InfopointReason reason;
 
     public FullInfopointOp(LIRFrameState state, InfopointReason reason) {
+        super(TYPE);
         this.state = state;
         this.reason = reason;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,24 +22,27 @@
  */
 package com.oracle.graal.lir;
 
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import java.lang.annotation.*;
+import java.util.*;
 
-import java.lang.annotation.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandMode.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
 import com.oracle.graal.lir.asm.*;
 
 /**
- * The {@code LIRInstruction} interface definition.
+ * The base class for an {@code LIRInstruction}.
  */
-public interface LIRInstruction {
-    Value[] NO_OPERANDS = {};
+public abstract class LIRInstruction {
+    public static final Value[] NO_OPERANDS = {};
 
     /**
      * Constants denoting how a LIR instruction uses an operand.
      */
-    enum OperandMode {
+    public enum OperandMode {
         /**
          * The value must have been defined before. It is alive before the instruction until the
          * beginning of the instruction, but not necessarily throughout the instruction. A register
@@ -72,41 +75,41 @@
 
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
-    static @interface Use {
+    public static @interface Use {
 
-        OperandFlag[] value() default REG;
+        OperandFlag[] value() default OperandFlag.REG;
     }
 
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
-    static @interface Alive {
+    public static @interface Alive {
 
-        OperandFlag[] value() default REG;
+        OperandFlag[] value() default OperandFlag.REG;
     }
 
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
-    static @interface Temp {
+    public static @interface Temp {
 
-        OperandFlag[] value() default REG;
+        OperandFlag[] value() default OperandFlag.REG;
     }
 
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
-    static @interface Def {
+    public static @interface Def {
 
-        OperandFlag[] value() default REG;
+        OperandFlag[] value() default OperandFlag.REG;
     }
 
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.FIELD)
-    static @interface State {
+    public static @interface State {
     }
 
     /**
      * Flags for an operand.
      */
-    enum OperandFlag {
+    public enum OperandFlag {
         /**
          * The value can be a {@link RegisterValue}.
          */
@@ -145,115 +148,205 @@
         UNINITIALIZED,
     }
 
-    void emitCode(CompilationResultBuilder crb);
+    /**
+     * For validity checking of the operand flags defined by instruction subclasses.
+     */
+    protected static final EnumMap<OperandMode, EnumSet<OperandFlag>> ALLOWED_FLAGS;
+
+    static {
+        ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
+        ALLOWED_FLAGS.put(OperandMode.USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
+        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, HINT));
+        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
+    }
 
-    int id();
+    /**
+     * The flags of the base and index value of an address.
+     */
+    protected static final EnumSet<OperandFlag> ADDRESS_FLAGS = EnumSet.of(REG, ILLEGAL);
+
+    private final LIRInstructionClass<?> instructionClass;
 
-    void setId(int id);
+    /**
+     * Instruction id for register allocation.
+     */
+    private int id;
+
+    private static final DebugMetric LIR_NODE_COUNT = Debug.metric("LIRNodes");
 
     /**
-     * Gets the instruction name.
+     * Constructs a new LIR instruction.
      */
-    String name();
+    public LIRInstruction(LIRInstructionClass<? extends LIRInstruction> c) {
+        LIR_NODE_COUNT.increment();
+        instructionClass = c;
+        assert c.getClazz() == this.getClass();
+        id = -1;
+    }
 
-    boolean hasOperands();
+    public abstract void emitCode(CompilationResultBuilder crb);
+
+    public final int id() {
+        return id;
+    }
 
-    boolean hasState();
+    public final void setId(int id) {
+        this.id = id;
+    }
+
+    public final String name() {
+        return instructionClass.getOpcode(this);
+    }
 
-    /**
-     * Determines if this instruction destroys all caller-saved registers..
-     */
-    boolean destroysCallerSavedRegisters();
+    public final boolean hasOperands() {
+        return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters();
+    }
+
+    public final boolean hasState() {
+        return instructionClass.hasState(this);
+    }
+
+    public boolean destroysCallerSavedRegisters() {
+        return false;
+    }
 
     // ValuePositionProcedures
-    void forEachInputPos(ValuePositionProcedure proc);
+    public final void forEachInputPos(ValuePositionProcedure proc) {
+        instructionClass.forEachUsePos(this, proc);
+    }
 
-    void forEachAlivePos(ValuePositionProcedure proc);
+    public final void forEachAlivePos(ValuePositionProcedure proc) {
+        instructionClass.forEachAlivePos(this, proc);
+    }
 
-    void forEachTempPos(ValuePositionProcedure proc);
+    public final void forEachTempPos(ValuePositionProcedure proc) {
+        instructionClass.forEachTempPos(this, proc);
+    }
 
-    void forEachOutputPos(ValuePositionProcedure proc);
+    public final void forEachOutputPos(ValuePositionProcedure proc) {
+        instructionClass.forEachDefPos(this, proc);
+    }
 
     // InstructionValueProcedures
-    void forEachInput(InstructionValueProcedure proc);
+    public final void forEachInput(InstructionValueProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
 
-    void forEachAlive(InstructionValueProcedure proc);
+    public final void forEachAlive(InstructionValueProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
 
-    void forEachTemp(InstructionValueProcedure proc);
+    public final void forEachTemp(InstructionValueProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
 
-    void forEachOutput(InstructionValueProcedure proc);
+    public final void forEachOutput(InstructionValueProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
 
-    void forEachState(InstructionValueProcedure proc);
+    public final void forEachState(InstructionValueProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
 
     // ValueProcedures
-    void forEachInput(ValueProcedure proc);
+    public final void forEachInput(ValueProcedure proc) {
+        instructionClass.forEachUse(this, proc);
+    }
 
-    void forEachAlive(ValueProcedure proc);
+    public final void forEachAlive(ValueProcedure proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
 
-    void forEachTemp(ValueProcedure proc);
+    public final void forEachTemp(ValueProcedure proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
 
-    void forEachOutput(ValueProcedure proc);
+    public final void forEachOutput(ValueProcedure proc) {
+        instructionClass.forEachDef(this, proc);
+    }
 
-    void forEachState(ValueProcedure proc);
+    public final void forEachState(ValueProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
 
     // States
-    void forEachState(InstructionStateProcedure proc);
+    public final void forEachState(InstructionStateProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
 
-    void forEachState(StateProcedure proc);
+    public final void forEachState(StateProcedure proc) {
+        instructionClass.forEachState(this, proc);
+    }
 
     // InstructionValueConsumers
-    void visitEachInput(InstructionValueConsumer proc);
+    public final void visitEachInput(InstructionValueConsumer proc) {
+        instructionClass.forEachUse(this, proc);
+    }
 
-    void visitEachAlive(InstructionValueConsumer proc);
+    public final void visitEachAlive(InstructionValueConsumer proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
 
-    void visitEachTemp(InstructionValueConsumer proc);
+    public final void visitEachTemp(InstructionValueConsumer proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
 
-    void visitEachOutput(InstructionValueConsumer proc);
+    public final void visitEachOutput(InstructionValueConsumer proc) {
+        instructionClass.forEachDef(this, proc);
+    }
 
-    void visitEachState(InstructionValueConsumer proc);
+    public final void visitEachState(InstructionValueConsumer proc) {
+        instructionClass.forEachState(this, proc);
+    }
 
     // ValueConsumers
-    void visitEachInput(ValueConsumer proc);
+    public final void visitEachInput(ValueConsumer proc) {
+        instructionClass.forEachUse(this, proc);
+    }
 
-    void visitEachAlive(ValueConsumer proc);
+    public final void visitEachAlive(ValueConsumer proc) {
+        instructionClass.forEachAlive(this, proc);
+    }
+
+    public final void visitEachTemp(ValueConsumer proc) {
+        instructionClass.forEachTemp(this, proc);
+    }
 
-    void visitEachTemp(ValueConsumer proc);
+    public final void visitEachOutput(ValueConsumer proc) {
+        instructionClass.forEachDef(this, proc);
+    }
 
-    void visitEachOutput(ValueConsumer proc);
+    public final void visitEachState(ValueConsumer proc) {
+        instructionClass.forEachState(this, proc);
+    }
 
-    void visitEachState(ValueConsumer proc);
+    @SuppressWarnings("unused")
+    public final Value forEachRegisterHint(Value value, OperandMode mode, InstructionValueProcedure proc) {
+        return instructionClass.forEachRegisterHint(this, mode, proc);
+    }
 
-    /**
-     * Iterates all register hints for the specified value, i.e., all preferred candidates for the
-     * register to be assigned to the value.
-     * <p>
-     * Subclasses can override this method. The default implementation processes all Input operands
-     * as the hints for an Output operand, and all Output operands as the hints for an Input
-     * operand.
-     *
-     * @param value The value the hints are needed for.
-     * @param mode The operand mode of the value.
-     * @param proc The procedure invoked for all the hints. If the procedure returns a non-null
-     *            value, the iteration is stopped and the value is returned by this method, i.e.,
-     *            clients can stop the iteration once a suitable hint has been found.
-     * @return The non-null value returned by the procedure, or null.
-     */
-    Value forEachRegisterHint(Value value, OperandMode mode, InstructionValueProcedure proc);
+    @SuppressWarnings("unused")
+    public final Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) {
+        return instructionClass.forEachRegisterHint(this, mode, proc);
+    }
+
+    public void verify() {
+    }
 
-    /**
-     * @see #forEachRegisterHint(Value, OperandMode, InstructionValueProcedure)
-     * @param value The value the hints are needed for.
-     * @param mode The operand mode of the value.
-     * @param proc The procedure invoked for all the hints. If the procedure returns a non-null
-     *            value, the iteration is stopped and the value is returned by this method, i.e.,
-     *            clients can stop the iteration once a suitable hint has been found.
-     * @return The non-null value returned by the procedure, or null.
-     */
-    Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc);
+    public final String toStringWithIdPrefix() {
+        if (id != -1) {
+            return String.format("%4d %s", id, toString());
+        }
+        return "     " + toString();
+    }
 
-    String toStringWithIdPrefix();
+    @Override
+    public String toString() {
+        return instructionClass.toString(this);
+    }
 
-    void verify();
-
-    LIRInstructionClass getLIRInstructionClass();
+    public LIRInstructionClass<?> getLIRInstructionClass() {
+        return instructionClass;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionBase.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2009, 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.lir;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandMode.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.lir.asm.*;
-
-/**
- * The base class for an {@code LIRInstruction}.
- */
-public abstract class LIRInstructionBase implements LIRInstruction {
-
-    /**
-     * For validity checking of the operand flags defined by instruction subclasses.
-     */
-    protected static final EnumMap<OperandMode, EnumSet<OperandFlag>> ALLOWED_FLAGS;
-
-    static {
-        ALLOWED_FLAGS = new EnumMap<>(OperandMode.class);
-        ALLOWED_FLAGS.put(USE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(ALIVE, EnumSet.of(REG, STACK, COMPOSITE, CONST, ILLEGAL, HINT, UNINITIALIZED));
-        ALLOWED_FLAGS.put(TEMP, EnumSet.of(REG, COMPOSITE, CONST, ILLEGAL, HINT));
-        ALLOWED_FLAGS.put(DEF, EnumSet.of(REG, STACK, COMPOSITE, ILLEGAL, HINT));
-    }
-
-    /**
-     * The flags of the base and index value of an address.
-     */
-    protected static final EnumSet<OperandFlag> ADDRESS_FLAGS = EnumSet.of(REG, ILLEGAL);
-
-    private final LIRInstructionClass instructionClass;
-
-    /**
-     * Instruction id for register allocation.
-     */
-    private int id;
-
-    private static final DebugMetric LIR_NODE_COUNT = Debug.metric("LIRNodes");
-
-    /**
-     * Constructs a new LIR instruction.
-     */
-    public LIRInstructionBase() {
-        LIR_NODE_COUNT.increment();
-        instructionClass = LIRInstructionClass.get(getClass());
-        id = -1;
-    }
-
-    public abstract void emitCode(CompilationResultBuilder crb);
-
-    public final int id() {
-        return id;
-    }
-
-    public final void setId(int id) {
-        this.id = id;
-    }
-
-    public final String name() {
-        return instructionClass.getOpcode(this);
-    }
-
-    public final boolean hasOperands() {
-        return instructionClass.hasOperands() || hasState() || destroysCallerSavedRegisters();
-    }
-
-    public final boolean hasState() {
-        return instructionClass.hasState(this);
-    }
-
-    public boolean destroysCallerSavedRegisters() {
-        return false;
-    }
-
-    // ValuePositionProcedures
-    public final void forEachInputPos(ValuePositionProcedure proc) {
-        instructionClass.forEachUsePos(this, proc);
-    }
-
-    public final void forEachAlivePos(ValuePositionProcedure proc) {
-        instructionClass.forEachAlivePos(this, proc);
-    }
-
-    public final void forEachTempPos(ValuePositionProcedure proc) {
-        instructionClass.forEachTempPos(this, proc);
-    }
-
-    public final void forEachOutputPos(ValuePositionProcedure proc) {
-        instructionClass.forEachDefPos(this, proc);
-    }
-
-    // InstructionValueProcedures
-    public final void forEachInput(InstructionValueProcedure proc) {
-        instructionClass.forEachUse(this, proc);
-    }
-
-    public final void forEachAlive(InstructionValueProcedure proc) {
-        instructionClass.forEachAlive(this, proc);
-    }
-
-    public final void forEachTemp(InstructionValueProcedure proc) {
-        instructionClass.forEachTemp(this, proc);
-    }
-
-    public final void forEachOutput(InstructionValueProcedure proc) {
-        instructionClass.forEachDef(this, proc);
-    }
-
-    public final void forEachState(InstructionValueProcedure proc) {
-        instructionClass.forEachState(this, proc);
-    }
-
-    // ValueProcedures
-    public final void forEachInput(ValueProcedure proc) {
-        instructionClass.forEachUse(this, proc);
-    }
-
-    public final void forEachAlive(ValueProcedure proc) {
-        instructionClass.forEachAlive(this, proc);
-    }
-
-    public final void forEachTemp(ValueProcedure proc) {
-        instructionClass.forEachTemp(this, proc);
-    }
-
-    public final void forEachOutput(ValueProcedure proc) {
-        instructionClass.forEachDef(this, proc);
-    }
-
-    public final void forEachState(ValueProcedure proc) {
-        instructionClass.forEachState(this, proc);
-    }
-
-    // States
-    public final void forEachState(InstructionStateProcedure proc) {
-        instructionClass.forEachState(this, proc);
-    }
-
-    public final void forEachState(StateProcedure proc) {
-        instructionClass.forEachState(this, proc);
-    }
-
-    // InstructionValueConsumers
-    public final void visitEachInput(InstructionValueConsumer proc) {
-        instructionClass.forEachUse(this, proc);
-    }
-
-    public final void visitEachAlive(InstructionValueConsumer proc) {
-        instructionClass.forEachAlive(this, proc);
-    }
-
-    public final void visitEachTemp(InstructionValueConsumer proc) {
-        instructionClass.forEachTemp(this, proc);
-    }
-
-    public final void visitEachOutput(InstructionValueConsumer proc) {
-        instructionClass.forEachDef(this, proc);
-    }
-
-    public final void visitEachState(InstructionValueConsumer proc) {
-        instructionClass.forEachState(this, proc);
-    }
-
-    // ValueConsumers
-    public final void visitEachInput(ValueConsumer proc) {
-        instructionClass.forEachUse(this, proc);
-    }
-
-    public final void visitEachAlive(ValueConsumer proc) {
-        instructionClass.forEachAlive(this, proc);
-    }
-
-    public final void visitEachTemp(ValueConsumer proc) {
-        instructionClass.forEachTemp(this, proc);
-    }
-
-    public final void visitEachOutput(ValueConsumer proc) {
-        instructionClass.forEachDef(this, proc);
-    }
-
-    public final void visitEachState(ValueConsumer proc) {
-        instructionClass.forEachState(this, proc);
-    }
-
-    public Value forEachRegisterHint(Value value, OperandMode mode, InstructionValueProcedure proc) {
-        return instructionClass.forEachRegisterHint(this, mode, proc);
-    }
-
-    public Value forEachRegisterHint(Value value, OperandMode mode, ValueProcedure proc) {
-        return instructionClass.forEachRegisterHint(this, mode, proc);
-    }
-
-    public void verify() {
-    }
-
-    public final String toStringWithIdPrefix() {
-        if (id != -1) {
-            return String.format("%4d %s", id, toString());
-        }
-        return "     " + toString();
-    }
-
-    @Override
-    public String toString() {
-        return instructionClass.toString(this);
-    }
-
-    public LIRInstructionClass getLIRInstructionClass() {
-        return instructionClass;
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,23 +31,10 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
-public class LIRInstructionClass extends LIRIntrospection {
-
-    public static final LIRInstructionClass get(Class<? extends LIRInstruction> c) {
-        LIRInstructionClass clazz = (LIRInstructionClass) allClasses.get(c);
-        if (clazz != null) {
-            return clazz;
-        }
+public class LIRInstructionClass<T> extends LIRIntrospection<T> {
 
-        // We can have a race of multiple threads creating the LIRInstructionClass at the same time.
-        // However, only one will be put into the map, and this is the one returned by all threads.
-        clazz = new LIRInstructionClass(c);
-        LIRInstructionClass oldClazz = (LIRInstructionClass) allClasses.putIfAbsent(c, clazz);
-        if (oldClazz != null) {
-            return oldClazz;
-        } else {
-            return clazz;
-        }
+    public static final <T extends LIRInstruction> LIRInstructionClass<T> create(Class<T> c) {
+        return new LIRInstructionClass<>(c);
     }
 
     private static final Class<LIRInstruction> INSTRUCTION_CLASS = LIRInstruction.class;
@@ -62,11 +49,11 @@
     private String opcodeConstant;
     private int opcodeIndex;
 
-    private LIRInstructionClass(Class<? extends LIRInstruction> clazz) {
+    private LIRInstructionClass(Class<T> clazz) {
         this(clazz, new FieldsScanner.DefaultCalcOffset());
     }
 
-    public LIRInstructionClass(Class<? extends LIRInstruction> clazz, FieldsScanner.CalcOffset calcOffset) {
+    public LIRInstructionClass(Class<T> clazz, FieldsScanner.CalcOffset calcOffset) {
         super(clazz);
         assert INSTRUCTION_CLASS.isAssignableFrom(clazz);
 
@@ -134,7 +121,7 @@
             }
             opcodeField = null;
 
-            super.scan(clazz, LIRInstructionBase.class, false);
+            super.scan(clazz, LIRInstruction.class, false);
 
             if (opcodeConstant == null && opcodeField == null) {
                 opcodeConstant = clazz.getSimpleName();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,7 +35,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
-abstract class LIRIntrospection extends FieldIntrospection {
+abstract class LIRIntrospection<T> extends FieldIntrospection<T> {
 
     private static final Class<Value> VALUE_CLASS = Value.class;
     private static final Class<JavaConstant> CONSTANT_CLASS = JavaConstant.class;
@@ -44,7 +44,7 @@
     private static final Class<StackSlot> STACK_SLOT_CLASS = StackSlot.class;
     private static final Class<Value[]> VALUE_ARRAY_CLASS = Value[].class;
 
-    public LIRIntrospection(Class<?> clazz) {
+    public LIRIntrospection(Class<T> clazz) {
         super(clazz);
     }
 
@@ -202,7 +202,7 @@
 
     protected static void forEach(LIRInstruction inst, Values values, OperandMode mode, InstructionValueProcedure proc) {
         for (int i = 0; i < values.getCount(); i++) {
-            assert LIRInstructionBase.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
             if (i < values.getDirectCount()) {
                 Value value = values.getValue(inst, i);
@@ -238,7 +238,7 @@
     protected static CompositeValue forEachComponent(LIRInstruction inst, CompositeValue obj, Values values, OperandMode mode, InstructionValueProcedure proc) {
         CompositeValue newCompValue = null;
         for (int i = 0; i < values.getCount(); i++) {
-            assert LIRInstructionBase.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
             if (i < values.getDirectCount()) {
                 Value value = values.getValue(obj, i);
@@ -286,7 +286,7 @@
 
     protected static void forEach(LIRInstruction inst, Object obj, Values values, OperandMode mode, ValuePositionProcedure proc, ValuePosition outerPosition) {
         for (int i = 0; i < values.getCount(); i++) {
-            assert LIRInstructionBase.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
+            assert LIRInstruction.ALLOWED_FLAGS.get(mode).containsAll(values.getFlags(i));
 
             if (i < values.getDirectCount()) {
                 Value value = values.getValue(obj, i);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,18 +24,20 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
 import com.oracle.graal.lir.StandardOp.NullCheck;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
-public final class NullCheckOptimizer {
+public final class NullCheckOptimizer extends PostAllocationOptimizationPhase {
 
-    public static void optimize(LIR ir, int implicitNullCheckLimit) {
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        LIR ir = lirGenRes.getLIR();
         List<? extends AbstractBlock<?>> blocks = ir.codeEmittingOrder();
-        NullCheckOptimizer.foldNullChecks(ir, blocks, implicitNullCheckLimit);
-    }
-
-    private NullCheckOptimizer() {
+        NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit);
     }
 
     private static void foldNullChecks(LIR ir, List<? extends AbstractBlock<?>> blocks, int implicitNullCheckLimit) {
@@ -63,4 +65,5 @@
             }
         }
     }
+
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,15 +35,18 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
 /**
  * Removes move instructions, where the destination value is already in place.
  */
-public final class RedundantMoveElimination {
+public final class RedundantMoveElimination extends PostAllocationOptimizationPhase {
 
-    public static void optimize(LIR lir, FrameMapBuilder frameMapBuilder) {
-        RedundantMoveElimination redundantMoveElimination = new RedundantMoveElimination();
-        redundantMoveElimination.doOptimize(lir, frameMapBuilder);
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        Optimization redundantMoveElimination = new Optimization();
+        redundantMoveElimination.doOptimize(lirGenRes.getLIR(), lirGenRes.getFrameMap());
     }
 
     /**
@@ -57,7 +60,7 @@
      * The value numbers also contain information if it is an object kind value or not: if the
      * number is negative it is an object kind value.
      */
-    private static class BlockData {
+    private static final class BlockData {
 
         BlockData(int stateSize) {
             entryState = new int[stateSize];
@@ -82,436 +85,440 @@
         int entryValueNum;
     }
 
-    Map<AbstractBlock<?>, BlockData> blockData = CollectionsFactory.newMap();
+    private static final class Optimization {
 
-    Register[] callerSaveRegs;
+        Map<AbstractBlock<?>, BlockData> blockData = CollectionsFactory.newMap();
+
+        Register[] callerSaveRegs;
 
-    /**
-     * Contains the register number for registers which can be optimized and -1 for the others.
-     */
-    int[] eligibleRegs;
+        /**
+         * Contains the register number for registers which can be optimized and -1 for the others.
+         */
+        int[] eligibleRegs;
+
+        Map<StackSlot, Integer> stackIndices = CollectionsFactory.newMap();
+
+        int numRegs;
+
+        /*
+         * Pseudo value for a not yet assigned location.
+         */
+        static final int INIT_VALUE = 0;
 
-    Map<StackSlot, Integer> stackIndices = CollectionsFactory.newMap();
+        /**
+         * The main method doing the elimination of redundant moves.
+         */
+        private void doOptimize(LIR lir, FrameMap frameMap) {
 
-    int numRegs;
+            try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) {
+
+                callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters();
 
-    /*
-     * Pseudo value for a not yet assigned location.
-     */
-    static final int INIT_VALUE = 0;
+                initBlockData(lir);
+
+                // Compute a table of the registers which are eligible for move optimization.
+                // Unallocatable registers should never be optimized.
+                eligibleRegs = new int[numRegs];
+                Arrays.fill(eligibleRegs, -1);
+                for (Register reg : frameMap.getRegisterConfig().getAllocatableRegisters()) {
+                    if (reg.number < numRegs) {
+                        eligibleRegs[reg.number] = reg.number;
+                    }
+                }
 
-    /**
-     * The main method doing the elimination of redundant moves.
-     */
-    private void doOptimize(LIR lir, FrameMapBuilder frameMapBuilder) {
+                if (!solveDataFlow(lir)) {
+                    return;
+                }
+
+                eliminateMoves(lir);
+            }
+        }
 
-        try (Indent indent = Debug.logAndIndent("eliminate redundant moves")) {
+        /**
+         * The maximum number of locations * blocks. This is a complexity limit for the inner loop
+         * in {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}.
+         */
+        private static final int COMPLEXITY_LIMIT = 30000;
 
-            callerSaveRegs = frameMapBuilder.getRegisterConfig().getCallerSaveRegisters();
+        private void initBlockData(LIR lir) {
+
+            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+            numRegs = 0;
+
+            int maxStackLocations = COMPLEXITY_LIMIT / blocks.size();
 
-            initBlockData(lir);
-
-            // Compute a table of the registers which are eligible for move optimization.
-            // Unallocatable registers should never be optimized.
-            eligibleRegs = new int[numRegs];
-            Arrays.fill(eligibleRegs, -1);
-            for (Register reg : frameMapBuilder.getRegisterConfig().getAllocatableRegisters()) {
-                if (reg.number < numRegs) {
-                    eligibleRegs[reg.number] = reg.number;
+            /*
+             * Search for relevant locations which can be optimized. These are register or stack
+             * slots which occur as destinations of move instructions.
+             */
+            for (AbstractBlock<?> block : blocks) {
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                for (LIRInstruction op : instructions) {
+                    if (isEligibleMove(op)) {
+                        Value dest = ((MoveOp) op).getResult();
+                        if (isRegister(dest)) {
+                            int regNum = ((RegisterValue) dest).getRegister().number;
+                            if (regNum >= numRegs) {
+                                numRegs = regNum + 1;
+                            }
+                        } else if (isStackSlot(dest)) {
+                            StackSlot stackSlot = (StackSlot) dest;
+                            if (!stackIndices.containsKey(stackSlot) && stackIndices.size() < maxStackLocations) {
+                                stackIndices.put(stackSlot, stackIndices.size());
+                            }
+                        }
+                    }
                 }
             }
 
-            if (!solveDataFlow(lir)) {
-                return;
+            /*
+             * Now we know the number of locations to optimize, so we can allocate the block states.
+             */
+            int numLocations = numRegs + stackIndices.size();
+            Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
+            for (AbstractBlock<?> block : blocks) {
+                BlockData data = new BlockData(numLocations);
+                blockData.put(block, data);
+            }
+        }
+
+        /**
+         * Calculates the entry and exit states for all basic blocks.
+         *
+         * @return Returns true on success and false if the the control flow is too complex.
+         */
+        private boolean solveDataFlow(LIR lir) {
+
+            try (Indent indent = Debug.logAndIndent("solve data flow")) {
+
+                List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+
+                int numIter = 0;
+
+                /*
+                 * Iterate until there are no more changes.
+                 */
+                int currentValueNum = 1;
+                boolean firstRound = true;
+                boolean changed;
+                do {
+                    changed = false;
+                    try (Indent indent2 = Debug.logAndIndent("new iteration")) {
+
+                        for (AbstractBlock<?> block : blocks) {
+
+                            BlockData data = blockData.get(block);
+                            /*
+                             * Initialize the number for global value numbering for this block. It
+                             * is essential that the starting number for a block is consistent at
+                             * all iterations and also in eliminateMoves().
+                             */
+                            if (firstRound) {
+                                data.entryValueNum = currentValueNum;
+                            }
+                            int valueNum = data.entryValueNum;
+                            assert valueNum > 0;
+                            boolean newState = false;
+
+                            if (block == blocks.get(0) || block.isExceptionEntry()) {
+                                /*
+                                 * The entry block has undefined values. And also exception handler
+                                 * blocks: the LinearScan can insert moves at the end of an
+                                 * exception handler predecessor block (after the invoke, which
+                                 * throws the exception), and in reality such moves are not in the
+                                 * control flow in case of an exception. So we assume a save default
+                                 * for exception handler blocks.
+                                 */
+                                Debug.log("kill all values at entry of block %d", block.getId());
+                                clearValues(data.entryState, valueNum);
+                            } else {
+                                /*
+                                 * Merge the states of predecessor blocks
+                                 */
+                                for (AbstractBlock<?> predecessor : block.getPredecessors()) {
+                                    BlockData predData = blockData.get(predecessor);
+                                    newState |= mergeState(data.entryState, predData.exitState, valueNum);
+                                }
+                            }
+                            // Advance by the value numbers which are "consumed" by
+                            // clearValues and mergeState
+                            valueNum += data.entryState.length;
+
+                            if (newState || firstRound) {
+                                try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) {
+
+                                    /*
+                                     * Derive the exit state from the entry state by iterating
+                                     * through all instructions of the block.
+                                     */
+                                    int[] iterState = data.exitState;
+                                    copyState(iterState, data.entryState);
+                                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+
+                                    for (LIRInstruction op : instructions) {
+                                        valueNum = updateState(iterState, op, valueNum);
+                                    }
+                                    changed = true;
+                                }
+                            }
+                            if (firstRound) {
+                                currentValueNum = valueNum;
+                            }
+                        }
+                        firstRound = false;
+                    }
+                    numIter++;
+
+                    if (numIter > 5) {
+                        /*
+                         * This is _very_ seldom.
+                         */
+                        return false;
+                    }
+
+                } while (changed);
+
             }
 
-            eliminateMoves(lir);
+            return true;
         }
-    }
+
+        /**
+         * Deletes all move instructions where the target location already contains the source
+         * value.
+         */
+        private void eliminateMoves(LIR lir) {
+
+            try (Indent indent = Debug.logAndIndent("eliminate moves")) {
 
-    /**
-     * The maximum number of locations * blocks. This is a complexity limit for the inner loop in
-     * {@link #mergeState} (assuming a small number of iterations in {@link #solveDataFlow}.
-     */
-    private static final int COMPLEXITY_LIMIT = 30000;
+                List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+
+                for (AbstractBlock<?> block : blocks) {
+
+                    try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
 
-    private void initBlockData(LIR lir) {
+                        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                        BlockData data = blockData.get(block);
+                        boolean hasDead = false;
 
-        List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
-        numRegs = 0;
-
-        int maxStackLocations = COMPLEXITY_LIMIT / blocks.size();
+                        // Reuse the entry state for iteration, we don't need it later.
+                        int[] iterState = data.entryState;
 
-        /*
-         * Search for relevant locations which can be optimized. These are register or stack slots
-         * which occur as destinations of move instructions.
-         */
-        for (AbstractBlock<?> block : blocks) {
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            for (LIRInstruction op : instructions) {
-                if (isEligibleMove(op)) {
-                    Value dest = ((MoveOp) op).getResult();
-                    if (isRegister(dest)) {
-                        int regNum = ((RegisterValue) dest).getRegister().number;
-                        if (regNum >= numRegs) {
-                            numRegs = regNum + 1;
+                        // Add the values which are "consumed" by clearValues and
+                        // mergeState in solveDataFlow
+                        int valueNum = data.entryValueNum + data.entryState.length;
+
+                        int numInsts = instructions.size();
+                        for (int idx = 0; idx < numInsts; idx++) {
+                            LIRInstruction op = instructions.get(idx);
+                            if (isEligibleMove(op)) {
+                                MoveOp moveOp = (MoveOp) op;
+                                int sourceIdx = getStateIdx(moveOp.getInput());
+                                int destIdx = getStateIdx(moveOp.getResult());
+                                if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
+                                    assert iterState[sourceIdx] != INIT_VALUE;
+                                    Debug.log("delete move %s", op);
+                                    instructions.set(idx, null);
+                                    hasDead = true;
+                                }
+                            }
+                            // It doesn't harm if updateState is also called for a deleted move
+                            valueNum = updateState(iterState, op, valueNum);
                         }
-                    } else if (isStackSlot(dest)) {
-                        StackSlot stackSlot = (StackSlot) dest;
-                        if (!stackIndices.containsKey(stackSlot) && stackIndices.size() < maxStackLocations) {
-                            stackIndices.put(stackSlot, stackIndices.size());
+                        if (hasDead) {
+                            instructions.removeAll(Collections.singleton(null));
                         }
                     }
                 }
             }
         }
 
-        /*
-         * Now we know the number of locations to optimize, so we can allocate the block states.
+        /**
+         * Updates the state for one instruction.
          */
-        int numLocations = numRegs + stackIndices.size();
-        Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
-        for (AbstractBlock<?> block : blocks) {
-            BlockData data = new BlockData(numLocations);
-            blockData.put(block, data);
-        }
-    }
-
-    /**
-     * Calculates the entry and exit states for all basic blocks.
-     *
-     * @return Returns true on success and false if the the control flow is too complex.
-     */
-    private boolean solveDataFlow(LIR lir) {
-
-        try (Indent indent = Debug.logAndIndent("solve data flow")) {
-
-            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+        private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
 
-            int numIter = 0;
+            try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
+                if (isEligibleMove(op)) {
+                    /*
+                     * Handle the special case of a move instruction
+                     */
+                    MoveOp moveOp = (MoveOp) op;
+                    int sourceIdx = getStateIdx(moveOp.getInput());
+                    int destIdx = getStateIdx(moveOp.getResult());
+                    if (sourceIdx >= 0 && destIdx >= 0) {
+                        assert isObjectValue(state[sourceIdx]) || moveOp.getInput().getLIRKind().isValue() : "move op moves object but input is not defined as object";
+                        state[destIdx] = state[sourceIdx];
+                        Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
+                        return initValueNum;
+                    }
+                }
 
-            /*
-             * Iterate until there are no more changes.
-             */
-            int currentValueNum = 1;
-            boolean firstRound = true;
-            boolean changed;
-            do {
-                changed = false;
-                try (Indent indent2 = Debug.logAndIndent("new iteration")) {
+                int valueNum = initValueNum;
+
+                if (op.destroysCallerSavedRegisters()) {
+                    Debug.log("kill all caller save regs");
 
-                    for (AbstractBlock<?> block : blocks) {
-
-                        BlockData data = blockData.get(block);
-                        /*
-                         * Initialize the number for global value numbering for this block. It is
-                         * essential that the starting number for a block is consistent at all
-                         * iterations and also in eliminateMoves().
-                         */
-                        if (firstRound) {
-                            data.entryValueNum = currentValueNum;
+                    for (Register reg : callerSaveRegs) {
+                        if (reg.number < numRegs) {
+                            // Kind.Object is the save default
+                            state[reg.number] = encodeValueNum(valueNum++, true);
                         }
-                        int valueNum = data.entryValueNum;
-                        assert valueNum > 0;
-                        boolean newState = false;
+                    }
+                }
+
+                /*
+                 * Value procedure for the instruction's output and temp values
+                 */
+                class OutputValueConsumer implements ValueConsumer {
 
-                        if (block == blocks.get(0) || block.isExceptionEntry()) {
+                    int opValueNum;
+
+                    OutputValueConsumer(int opValueNum) {
+                        this.opValueNum = opValueNum;
+                    }
+
+                    @Override
+                    public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                        int stateIdx = getStateIdx(operand);
+                        if (stateIdx >= 0) {
                             /*
-                             * The entry block has undefined values. And also exception handler
-                             * blocks: the LinearScan can insert moves at the end of an exception
-                             * handler predecessor block (after the invoke, which throws the
-                             * exception), and in reality such moves are not in the control flow in
-                             * case of an exception. So we assume a save default for exception
-                             * handler blocks.
-                             */
-                            Debug.log("kill all values at entry of block %d", block.getId());
-                            clearValues(data.entryState, valueNum);
-                        } else {
-                            /*
-                             * Merge the states of predecessor blocks
+                             * Assign a unique number to the output or temp location.
                              */
-                            for (AbstractBlock<?> predecessor : block.getPredecessors()) {
-                                BlockData predData = blockData.get(predecessor);
-                                newState |= mergeState(data.entryState, predData.exitState, valueNum);
-                            }
-                        }
-                        // Advance by the value numbers which are "consumed" by
-                        // clearValues and mergeState
-                        valueNum += data.entryState.length;
-
-                        if (newState || firstRound) {
-                            try (Indent indent3 = Debug.logAndIndent("update block %d", block.getId())) {
-
-                                /*
-                                 * Derive the exit state from the entry state by iterating through
-                                 * all instructions of the block.
-                                 */
-                                int[] iterState = data.exitState;
-                                copyState(iterState, data.entryState);
-                                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-
-                                for (LIRInstruction op : instructions) {
-                                    valueNum = updateState(iterState, op, valueNum);
-                                }
-                                changed = true;
-                            }
-                        }
-                        if (firstRound) {
-                            currentValueNum = valueNum;
+                            state[stateIdx] = encodeValueNum(opValueNum++, !operand.getLIRKind().isValue());
+                            Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
                         }
                     }
-                    firstRound = false;
-                }
-                numIter++;
-
-                if (numIter > 5) {
-                    /*
-                     * This is _very_ seldom.
-                     */
-                    return false;
                 }
 
-            } while (changed);
+                OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);
+
+                op.visitEachTemp(outputValueConsumer);
+                /*
+                 * Semantically the output values are written _after_ the temp values
+                 */
+                op.visitEachOutput(outputValueConsumer);
+
+                valueNum = outputValueConsumer.opValueNum;
 
+                if (op.hasState()) {
+                    /*
+                     * All instructions with framestates (mostly method calls), may do garbage
+                     * collection. GC will rewrite all object references which are live at this
+                     * point. So we can't rely on their values. It would be sufficient to just kill
+                     * all values which are referenced in the state (or all values which are not),
+                     * but for simplicity we kill all values.
+                     */
+                    Debug.log("kill all object values");
+                    clearValuesOfKindObject(state, valueNum);
+                    valueNum += state.length;
+                }
+
+                return valueNum;
+            }
         }
 
-        return true;
-    }
-
-    /**
-     * Deletes all move instructions where the target location already contains the source value.
-     */
-    private void eliminateMoves(LIR lir) {
-
-        try (Indent indent = Debug.logAndIndent("eliminate moves")) {
-
-            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
-
-            for (AbstractBlock<?> block : blocks) {
-
-                try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
-
-                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-                    BlockData data = blockData.get(block);
-                    boolean hasDead = false;
-
-                    // Reuse the entry state for iteration, we don't need it later.
-                    int[] iterState = data.entryState;
+        /**
+         * The state merge function for dataflow joins.
+         */
+        private static boolean mergeState(int[] dest, int[] source, int defNum) {
+            assert dest.length == source.length;
+            boolean changed = false;
+            for (int idx = 0; idx < source.length; idx++) {
+                int phiNum = defNum + idx;
+                int dst = dest[idx];
+                int src = source[idx];
+                if (dst != src && src != INIT_VALUE && dst != encodeValueNum(phiNum, isObjectValue(dst))) {
+                    if (dst != INIT_VALUE) {
+                        dst = encodeValueNum(phiNum, isObjectValue(dst) || isObjectValue(src));
+                    } else {
+                        dst = src;
+                    }
+                    dest[idx] = dst;
+                    changed = true;
+                }
+            }
+            return changed;
+        }
 
-                    // Add the values which are "consumed" by clearValues and
-                    // mergeState in solveDataFlow
-                    int valueNum = data.entryValueNum + data.entryState.length;
+        private static void copyState(int[] dest, int[] source) {
+            assert dest.length == source.length;
+            for (int idx = 0; idx < source.length; idx++) {
+                dest[idx] = source[idx];
+            }
+        }
 
-                    int numInsts = instructions.size();
-                    for (int idx = 0; idx < numInsts; idx++) {
-                        LIRInstruction op = instructions.get(idx);
-                        if (isEligibleMove(op)) {
-                            MoveOp moveOp = (MoveOp) op;
-                            int sourceIdx = getStateIdx(moveOp.getInput());
-                            int destIdx = getStateIdx(moveOp.getResult());
-                            if (sourceIdx >= 0 && destIdx >= 0 && iterState[sourceIdx] == iterState[destIdx]) {
-                                assert iterState[sourceIdx] != INIT_VALUE;
-                                Debug.log("delete move %s", op);
-                                instructions.set(idx, null);
-                                hasDead = true;
-                            }
-                        }
-                        // It doesn't harm if updateState is also called for a deleted move
-                        valueNum = updateState(iterState, op, valueNum);
-                    }
-                    if (hasDead) {
-                        instructions.removeAll(Collections.singleton(null));
-                    }
+        private static void clearValues(int[] state, int defNum) {
+            for (int idx = 0; idx < state.length; idx++) {
+                int phiNum = defNum + idx;
+                // Let the killed values assume to be object references: it's the save default.
+                state[idx] = encodeValueNum(phiNum, true);
+            }
+        }
+
+        private static void clearValuesOfKindObject(int[] state, int defNum) {
+            for (int idx = 0; idx < state.length; idx++) {
+                int phiNum = defNum + idx;
+                if (isObjectValue(state[idx])) {
+                    state[idx] = encodeValueNum(phiNum, true);
                 }
             }
         }
-    }
 
-    /**
-     * Updates the state for one instruction.
-     */
-    private int updateState(final int[] state, LIRInstruction op, int initValueNum) {
-
-        try (final Indent indent = Debug.logAndIndent("update state for op %s, initial value num = %d", op, initValueNum)) {
-            if (isEligibleMove(op)) {
-                /*
-                 * Handle the special case of a move instruction
-                 */
-                MoveOp moveOp = (MoveOp) op;
-                int sourceIdx = getStateIdx(moveOp.getInput());
-                int destIdx = getStateIdx(moveOp.getResult());
-                if (sourceIdx >= 0 && destIdx >= 0) {
-                    assert isObjectValue(state[sourceIdx]) || moveOp.getInput().getLIRKind().isValue() : "move op moves object but input is not defined as object";
-                    state[destIdx] = state[sourceIdx];
-                    Debug.log("move value %d from %d to %d", state[sourceIdx], sourceIdx, destIdx);
-                    return initValueNum;
+        /**
+         * Returns the index to the state arrays in BlockData for a specific location.
+         */
+        private int getStateIdx(Value location) {
+            if (isRegister(location)) {
+                int regNum = ((RegisterValue) location).getRegister().number;
+                if (regNum < numRegs) {
+                    return eligibleRegs[regNum];
                 }
-            }
-
-            int valueNum = initValueNum;
-
-            if (op.destroysCallerSavedRegisters()) {
-                Debug.log("kill all caller save regs");
-
-                for (Register reg : callerSaveRegs) {
-                    if (reg.number < numRegs) {
-                        // Kind.Object is the save default
-                        state[reg.number] = encodeValueNum(valueNum++, true);
-                    }
-                }
-            }
-
-            /*
-             * Value procedure for the instruction's output and temp values
-             */
-            class OutputValueConsumer implements ValueConsumer {
-
-                int opValueNum;
-
-                OutputValueConsumer(int opValueNum) {
-                    this.opValueNum = opValueNum;
-                }
-
-                @Override
-                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                    int stateIdx = getStateIdx(operand);
-                    if (stateIdx >= 0) {
-                        /*
-                         * Assign a unique number to the output or temp location.
-                         */
-                        state[stateIdx] = encodeValueNum(opValueNum++, !operand.getLIRKind().isValue());
-                        Debug.log("set def %d for register %s(%d): %d", opValueNum, operand, stateIdx, state[stateIdx]);
-                    }
-                }
+                return -1;
             }
-
-            OutputValueConsumer outputValueConsumer = new OutputValueConsumer(valueNum);
-
-            op.visitEachTemp(outputValueConsumer);
-            /*
-             * Semantically the output values are written _after_ the temp values
-             */
-            op.visitEachOutput(outputValueConsumer);
-
-            valueNum = outputValueConsumer.opValueNum;
-
-            if (op.hasState()) {
-                /*
-                 * All instructions with framestates (mostly method calls), may do garbage
-                 * collection. GC will rewrite all object references which are live at this point.
-                 * So we can't rely on their values. It would be sufficient to just kill all values
-                 * which are referenced in the state (or all values which are not), but for
-                 * simplicity we kill all values.
-                 */
-                Debug.log("kill all object values");
-                clearValuesOfKindObject(state, valueNum);
-                valueNum += state.length;
-            }
-
-            return valueNum;
-        }
-    }
-
-    /**
-     * The state merge function for dataflow joins.
-     */
-    private static boolean mergeState(int[] dest, int[] source, int defNum) {
-        assert dest.length == source.length;
-        boolean changed = false;
-        for (int idx = 0; idx < source.length; idx++) {
-            int phiNum = defNum + idx;
-            int dst = dest[idx];
-            int src = source[idx];
-            if (dst != src && src != INIT_VALUE && dst != encodeValueNum(phiNum, isObjectValue(dst))) {
-                if (dst != INIT_VALUE) {
-                    dst = encodeValueNum(phiNum, isObjectValue(dst) || isObjectValue(src));
-                } else {
-                    dst = src;
+            if (isStackSlot(location)) {
+                StackSlot slot = (StackSlot) location;
+                Integer index = stackIndices.get(slot);
+                if (index != null) {
+                    return index.intValue() + numRegs;
                 }
-                dest[idx] = dst;
-                changed = true;
-            }
-        }
-        return changed;
-    }
-
-    private static void copyState(int[] dest, int[] source) {
-        assert dest.length == source.length;
-        for (int idx = 0; idx < source.length; idx++) {
-            dest[idx] = source[idx];
-        }
-    }
-
-    private static void clearValues(int[] state, int defNum) {
-        for (int idx = 0; idx < state.length; idx++) {
-            int phiNum = defNum + idx;
-            // Let the killed values assume to be object references: it's the save default.
-            state[idx] = encodeValueNum(phiNum, true);
-        }
-    }
-
-    private static void clearValuesOfKindObject(int[] state, int defNum) {
-        for (int idx = 0; idx < state.length; idx++) {
-            int phiNum = defNum + idx;
-            if (isObjectValue(state[idx])) {
-                state[idx] = encodeValueNum(phiNum, true);
-            }
-        }
-    }
-
-    /**
-     * Returns the index to the state arrays in BlockData for a specific location.
-     */
-    private int getStateIdx(Value location) {
-        if (isRegister(location)) {
-            int regNum = ((RegisterValue) location).getRegister().number;
-            if (regNum < numRegs) {
-                return eligibleRegs[regNum];
             }
             return -1;
         }
-        if (isStackSlot(location)) {
-            StackSlot slot = (StackSlot) location;
-            Integer index = stackIndices.get(slot);
-            if (index != null) {
-                return index.intValue() + numRegs;
+
+        /**
+         * Encodes a value number + the is-object information to a number to be stored in a state.
+         */
+        private static int encodeValueNum(int valueNum, boolean isObjectKind) {
+            assert valueNum > 0;
+            if (isObjectKind) {
+                return -valueNum;
             }
+            return valueNum;
         }
-        return -1;
-    }
-
-    /**
-     * Encodes a value number + the is-object information to a number to be stored in a state.
-     */
-    private static int encodeValueNum(int valueNum, boolean isObjectKind) {
-        assert valueNum > 0;
-        if (isObjectKind) {
-            return -valueNum;
-        }
-        return valueNum;
-    }
 
-    /**
-     * Returns true if an encoded value number (which is stored in a state) refers to an object
-     * reference.
-     */
-    private static boolean isObjectValue(int encodedValueNum) {
-        return encodedValueNum < 0;
-    }
+        /**
+         * Returns true if an encoded value number (which is stored in a state) refers to an object
+         * reference.
+         */
+        private static boolean isObjectValue(int encodedValueNum) {
+            return encodedValueNum < 0;
+        }
 
-    /**
-     * Returns true for a move instruction which is a candidate for elimination.
-     */
-    private static boolean isEligibleMove(LIRInstruction op) {
-        if (op instanceof MoveOp) {
-            MoveOp moveOp = (MoveOp) op;
-            Value source = moveOp.getInput();
-            Value dest = moveOp.getResult();
-            /*
-             * Moves with mismatching kinds are not moves, but memory loads/stores!
-             */
-            return source.getLIRKind().equals(dest.getLIRKind());
+        /**
+         * Returns true for a move instruction which is a candidate for elimination.
+         */
+        private static boolean isEligibleMove(LIRInstruction op) {
+            if (op instanceof MoveOp) {
+                MoveOp moveOp = (MoveOp) op;
+                Value source = moveOp.getInput();
+                Value dest = moveOp.getResult();
+                /*
+                 * Moves with mismatching kinds are not moves, but memory loads/stores!
+                 */
+                return source.getLIRKind().equals(dest.getLIRKind());
+            }
+            return false;
         }
-        return false;
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -26,11 +26,13 @@
 import com.oracle.graal.lir.asm.*;
 
 @Opcode("SIMPLE_INFOPOINT")
-public class SimpleInfopointOp extends LIRInstructionBase {
+public final class SimpleInfopointOp extends LIRInstruction {
+    public static final LIRInstructionClass<SimpleInfopointOp> TYPE = LIRInstructionClass.create(SimpleInfopointOp.class);
     private final InfopointReason reason;
     private final BytecodePosition position;
 
     public SimpleInfopointOp(InfopointReason reason, BytecodePosition position) {
+        super(TYPE);
         this.reason = reason;
         this.position = position;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Sat Feb 21 19:55:33 2015 +0100
@@ -44,23 +44,24 @@
      * A block delimiter. Every well formed block must contain exactly one such operation and it
      * must be the last operation in the block.
      */
-    public interface BlockEndOp extends LIRInstruction {
+    public interface BlockEndOp {
     }
 
-    public interface NullCheck extends LIRInstruction {
+    public interface NullCheck {
         Value getCheckedValue();
 
         LIRFrameState getState();
     }
 
-    public interface ImplicitNullCheck extends LIRInstruction {
+    public interface ImplicitNullCheck {
         boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit);
     }
 
     /**
      * LIR operation that defines the position of a label.
      */
-    public static class LabelOp extends LIRInstructionBase {
+    public static final class LabelOp extends LIRInstruction {
+        public static final LIRInstructionClass<LabelOp> TYPE = LIRInstructionClass.create(LabelOp.class);
 
         private static final Value[] NO_VALUES = new Value[0];
 
@@ -78,6 +79,7 @@
         private final boolean align;
 
         public LabelOp(Label label, boolean align) {
+            super(TYPE);
             this.label = label;
             this.align = align;
             this.incomingValues = NO_VALUES;
@@ -104,11 +106,17 @@
     /**
      * LIR operation that is an unconditional jump to a {@link #destination()}.
      */
-    public static class JumpOp extends LIRInstructionBase implements BlockEndOp {
+    public static class JumpOp extends LIRInstruction implements BlockEndOp {
+        public static final LIRInstructionClass<JumpOp> TYPE = LIRInstructionClass.create(JumpOp.class);
 
         private final LabelRef destination;
 
         public JumpOp(LabelRef destination) {
+            this(TYPE, destination);
+        }
+
+        protected JumpOp(LIRInstructionClass<? extends JumpOp> c, LabelRef destination) {
+            super(c);
             this.destination = destination;
         }
 
@@ -134,7 +142,7 @@
      * Marker interface for a LIR operation that moves a value from {@link #getInput()} to
      * {@link #getResult()}.
      */
-    public interface MoveOp extends LIRInstruction {
+    public interface MoveOp {
 
         Value getInput();
 
@@ -146,7 +154,7 @@
      * {@linkplain #remove(Set) pruned} and a mapping from registers to the frame slots in which
      * they are saved can be {@linkplain #getMap(FrameMap) retrieved}.
      */
-    public interface SaveRegistersOp extends LIRInstruction {
+    public interface SaveRegistersOp {
 
         /**
          * Determines if the {@link #remove(Set)} operation is supported for this object.
@@ -178,7 +186,8 @@
      * A LIR operation that does nothing. If the operation records its position, it can be
      * subsequently {@linkplain #replace(LIR, LIRInstruction) replaced}.
      */
-    public static class NoOp extends LIRInstructionBase {
+    public static final class NoOp extends LIRInstruction {
+        public static final LIRInstructionClass<NoOp> TYPE = LIRInstructionClass.create(NoOp.class);
 
         /**
          * The block in which this instruction is located.
@@ -191,6 +200,7 @@
         final int index;
 
         public NoOp(AbstractBlock<?> block, int index) {
+            super(TYPE);
             this.block = block;
             this.index = index;
         }
@@ -208,11 +218,13 @@
     }
 
     @Opcode("BLACKHOLE")
-    public static class BlackholeOp extends LIRInstructionBase {
+    public static final class BlackholeOp extends LIRInstruction {
+        public static final LIRInstructionClass<BlackholeOp> TYPE = LIRInstructionClass.create(BlackholeOp.class);
 
         @Use({REG, STACK}) private Value value;
 
         public BlackholeOp(Value value) {
+            super(TYPE);
             this.value = value;
         }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,7 +31,7 @@
 
 /**
  * This class encapsulates different strategies on how to generate code for switch instructions.
- * 
+ *
  * The {@link #getBestStrategy(double[], JavaConstant[], LabelRef[])} method can be used to get
  * strategy with the smallest average effort (average number of comparisons until a decision is
  * reached). The strategy returned by this method will have its averageEffort set, while a strategy
@@ -43,7 +43,7 @@
         /**
          * Generates a conditional or unconditional jump. The jump will be unconditional if
          * condition is null. If defaultTarget is true, then the jump will go the the default.
-         * 
+         *
          * @param index Index of the value and the jump target (only used if defaultTarget == false)
          * @param condition The condition on which to jump (can be null)
          * @param defaultTarget true if the jump should go to the default target, false if index
@@ -54,7 +54,7 @@
         /**
          * Generates a conditional jump to the target with the specified index. The fall through
          * should go to the default target.
-         * 
+         *
          * @param index Index of the value and the jump target
          * @param condition The condition on which to jump
          * @param canFallThrough true if this is the last instruction in the switch statement, to
@@ -64,7 +64,7 @@
 
         /**
          * Create a new label and generate a conditional jump to it.
-         * 
+         *
          * @param index Index of the value and the jump target
          * @param condition The condition on which to jump
          * @return a new Label
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Sat Feb 21 19:55:33 2015 +0100
@@ -56,7 +56,7 @@
  * >"Optimized Interval Splitting in a Linear Scan Register Allocator"</a> by Christian Wimmer and
  * Hanspeter Moessenboeck.
  */
-public final class LinearScan {
+final class LinearScan {
 
     final TargetDescription target;
     final LIRGenerationResult res;
@@ -109,7 +109,7 @@
         public BitSet liveKill;
     }
 
-    public final BlockMap<BlockData> blockData;
+    final BlockMap<BlockData> blockData;
 
     /**
      * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
@@ -161,7 +161,7 @@
      */
     private final int firstVariableNumber;
 
-    public LinearScan(TargetDescription target, LIRGenerationResult res) {
+    LinearScan(TargetDescription target, LIRGenerationResult res) {
         this.target = target;
         this.res = res;
         this.ir = res.getLIR();
@@ -178,13 +178,13 @@
         this.callKillsRegisters = this.frameMapBuilder.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
     }
 
-    public int getFirstLirInstructionId(AbstractBlock<?> block) {
+    int getFirstLirInstructionId(AbstractBlock<?> block) {
         int result = ir.getLIRforBlock(block).get(0).id();
         assert result >= 0;
         return result;
     }
 
-    public int getLastLirInstructionId(AbstractBlock<?> block) {
+    int getLastLirInstructionId(AbstractBlock<?> block) {
         List<LIRInstruction> instructions = ir.getLIRforBlock(block);
         int result = instructions.get(instructions.size() - 1).id();
         assert result >= 0;
@@ -220,7 +220,7 @@
     /**
      * Gets the highest operand number for a register operand. This value will never change.
      */
-    public int maxRegisterNumber() {
+    int maxRegisterNumber() {
         return firstVariableNumber - 1;
     }
 
@@ -1374,7 +1374,7 @@
         sortedIntervals = combinedList;
     }
 
-    public void allocateRegisters() {
+    void allocateRegisters() {
         try (Indent indent = Debug.logAndIndent("allocate registers")) {
             Interval precoloredIntervals;
             Interval notPrecoloredIntervals;
@@ -1731,11 +1731,7 @@
         }
     }
 
-    public static void allocate(TargetDescription target, LIRGenerationResult res) {
-        new LinearScan(target, res).allocate();
-    }
-
-    private void allocate() {
+    void allocate() {
 
         /*
          * This is the point to enable debug logging for the whole register allocation.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,39 @@
+/*
+ * 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.alloc.lsra;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
+
+public final class LinearScanPhase extends AllocationPhase {
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        new LinearScan(target, lirGenRes).allocate();
+    }
+
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,9 +34,15 @@
 import com.oracle.graal.lir.LIRInstruction.OperandFlag;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.framemap.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
-public final class LocationMarker {
+/**
+ * Mark all live references for a frame state. The frame state use this information to build the OOP
+ * maps.
+ */
+public final class LocationMarker extends AllocationPhase {
 
     public static class Options {
         // @formatter:off
@@ -45,177 +51,177 @@
         // @formatter:on
     }
 
-    /**
-     * Mark all live references for a frame state. The frame state use this information to build the
-     * OOP maps.
-     */
-    public static void markLocations(LIR lir, FrameMap frameMap) {
-        new LocationMarker(lir, frameMap).build();
-    }
-
-    private final LIR lir;
-    private final FrameMap frameMap;
-    private final RegisterAttributes[] registerAttributes;
-    private final BlockMap<ReferenceMap> liveInMap;
-    private final BlockMap<ReferenceMap> liveOutMap;
-
-    private LocationMarker(LIR lir, FrameMap frameMap) {
-        this.lir = lir;
-        this.frameMap = frameMap;
-        this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
-        liveInMap = new BlockMap<>(lir.getControlFlowGraph());
-        liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
-    private void build() {
-        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
-        for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
-            worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
-        }
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-            liveInMap.put(block, frameMap.initReferenceMap(true));
-        }
-        while (!worklist.isEmpty()) {
-            AbstractBlock<?> block = worklist.poll();
-            processBlock(block, worklist);
-        }
-        // finish states
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            for (int i = instructions.size() - 1; i >= 0; i--) {
-                LIRInstruction inst = instructions.get(i);
-                inst.forEachState((op, info) -> info.finish(op, frameMap));
-            }
+    private static final class Marker {
+        private final LIR lir;
+        private final FrameMap frameMap;
+        private final RegisterAttributes[] registerAttributes;
+        private final BlockMap<ReferenceMap> liveInMap;
+        private final BlockMap<ReferenceMap> liveOutMap;
 
+        private Marker(LIR lir, FrameMap frameMap) {
+            this.lir = lir;
+            this.frameMap = frameMap;
+            this.registerAttributes = frameMap.getRegisterConfig().getAttributesMap();
+            liveInMap = new BlockMap<>(lir.getControlFlowGraph());
+            liveOutMap = new BlockMap<>(lir.getControlFlowGraph());
         }
-    }
 
-    /**
-     * Merge outSet with in-set of successors.
-     */
-    private boolean updateOutBlock(AbstractBlock<?> block) {
-        ReferenceMap union = frameMap.initReferenceMap(true);
-        block.getSuccessors().forEach(succ -> union.updateUnion(liveInMap.get(succ)));
-        ReferenceMap outSet = liveOutMap.get(block);
-        // check if changed
-        if (outSet == null || !union.equals(outSet)) {
-            liveOutMap.put(block, union);
-            return true;
-        }
-        return false;
-    }
-
-    private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
-        if (updateOutBlock(block)) {
-            try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
-                BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
+        private void build() {
+            Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+            for (int i = lir.getControlFlowGraph().getBlocks().size() - 1; i >= 0; i--) {
+                worklist.add(lir.getControlFlowGraph().getBlocks().get(i));
+            }
+            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+                liveInMap.put(block, frameMap.initReferenceMap(true));
+            }
+            while (!worklist.isEmpty()) {
+                AbstractBlock<?> block = worklist.poll();
+                processBlock(block, worklist);
+            }
+            // finish states
+            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
                 List<LIRInstruction> instructions = lir.getLIRforBlock(block);
                 for (int i = instructions.size() - 1; i >= 0; i--) {
                     LIRInstruction inst = instructions.get(i);
-                    closure.processInstructionBottomUp(inst);
+                    inst.forEachState((op, info) -> info.finish(op, frameMap));
                 }
-                liveInMap.put(block, closure.getCurrentSet());
-                worklist.addAll(block.getPredecessors());
-            }
-        }
-    }
-
-    private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
-    private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
-
-    private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) {
-        if (op.destroysCallerSavedRegisters()) {
-            for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
-                consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
-            }
-        }
-    }
-
-    private final class BlockClosure {
-        private final ReferenceMap currentSet;
 
-        private BlockClosure(ReferenceMap set) {
-            currentSet = set;
-        }
-
-        private ReferenceMap getCurrentSet() {
-            return currentSet;
-        }
-
-        /**
-         * Process all values of an instruction bottom-up, i.e. definitions before usages. Values
-         * that start or end at the current operation are not included.
-         */
-        private void processInstructionBottomUp(LIRInstruction op) {
-            try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
-                // kills
-                op.visitEachTemp(this::defConsumer);
-                op.visitEachOutput(this::defConsumer);
-                forEachDestroyedCallerSavedRegister(op, this::defConsumer);
-
-                // gen - values that are considered alive for this state
-                op.visitEachAlive(this::useConsumer);
-                op.visitEachState(this::useConsumer);
-                // mark locations
-                op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet()));
-                // gen
-                op.visitEachInput(this::useConsumer);
             }
         }
 
         /**
-         * @see InstructionValueConsumer
-         * @param operand
-         * @param mode
-         * @param flags
+         * Merge outSet with in-set of successors.
          */
-        private void useConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            LIRKind kind = operand.getLIRKind();
-            if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
-                // no need to insert values and derived reference
-                Debug.log("set operand: %s", operand);
-                frameMap.setReference(operand, currentSet);
+        private boolean updateOutBlock(AbstractBlock<?> block) {
+            ReferenceMap union = frameMap.initReferenceMap(true);
+            block.getSuccessors().forEach(succ -> union.updateUnion(liveInMap.get(succ)));
+            ReferenceMap outSet = liveOutMap.get(block);
+            // check if changed
+            if (outSet == null || !union.equals(outSet)) {
+                liveOutMap.put(block, union);
+                return true;
+            }
+            return false;
+        }
+
+        private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
+            if (updateOutBlock(block)) {
+                try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
+                    BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
+                    List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                    for (int i = instructions.size() - 1; i >= 0; i--) {
+                        LIRInstruction inst = instructions.get(i);
+                        closure.processInstructionBottomUp(inst);
+                    }
+                    liveInMap.put(block, closure.getCurrentSet());
+                    worklist.addAll(block.getPredecessors());
+                }
+            }
+        }
+
+        private static final EnumSet<OperandFlag> REGISTER_FLAG_SET = EnumSet.of(OperandFlag.REG);
+        private static final LIRKind REFERENCE_KIND = LIRKind.reference(Kind.Object);
+
+        private void forEachDestroyedCallerSavedRegister(LIRInstruction op, ValueConsumer consumer) {
+            if (op.destroysCallerSavedRegisters()) {
+                for (Register reg : frameMap.getRegisterConfig().getCallerSaveRegisters()) {
+                    consumer.visitValue(reg.asValue(REFERENCE_KIND), OperandMode.TEMP, REGISTER_FLAG_SET);
+                }
+            }
+        }
+
+        private final class BlockClosure {
+            private final ReferenceMap currentSet;
+
+            private BlockClosure(ReferenceMap set) {
+                currentSet = set;
+            }
+
+            private ReferenceMap getCurrentSet() {
+                return currentSet;
+            }
+
+            /**
+             * Process all values of an instruction bottom-up, i.e. definitions before usages.
+             * Values that start or end at the current operation are not included.
+             */
+            private void processInstructionBottomUp(LIRInstruction op) {
+                try (Indent indent = Debug.logAndIndent("handle op %d, %s", op.id(), op)) {
+                    // kills
+                    op.visitEachTemp(this::defConsumer);
+                    op.visitEachOutput(this::defConsumer);
+                    forEachDestroyedCallerSavedRegister(op, this::defConsumer);
+
+                    // gen - values that are considered alive for this state
+                    op.visitEachAlive(this::useConsumer);
+                    op.visitEachState(this::useConsumer);
+                    // mark locations
+                    op.forEachState((inst, info) -> markLocation(inst, info, this.getCurrentSet()));
+                    // gen
+                    op.visitEachInput(this::useConsumer);
+                }
+            }
+
+            /**
+             * @see InstructionValueConsumer
+             * @param operand
+             * @param mode
+             * @param flags
+             */
+            private void useConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                LIRKind kind = operand.getLIRKind();
+                if (shouldProcessValue(operand) && !kind.isValue() && !kind.isDerivedReference()) {
+                    // no need to insert values and derived reference
+                    Debug.log("set operand: %s", operand);
+                    frameMap.setReference(operand, currentSet);
+                }
+            }
+
+            /**
+             * @see InstructionValueConsumer
+             * @param operand
+             * @param mode
+             * @param flags
+             */
+            private void defConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                if (shouldProcessValue(operand)) {
+                    Debug.log("clear operand: %s", operand);
+                    frameMap.clearReference(operand, currentSet);
+                } else {
+                    assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
+                                    operand, mode);
+                }
+            }
+
+            protected boolean shouldProcessValue(Value operand) {
+                return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
             }
         }
 
         /**
-         * @see InstructionValueConsumer
-         * @param operand
-         * @param mode
-         * @param flags
+         * This method does the actual marking.
          */
-        private void defConsumer(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-            if (shouldProcessValue(operand)) {
-                Debug.log("clear operand: %s", operand);
-                frameMap.clearReference(operand, currentSet);
-            } else {
-                assert isIllegal(operand) || operand.getPlatformKind() != Kind.Illegal || mode == OperandMode.TEMP : String.format("Illegal PlatformKind is only allowed for TEMP mode: %s, %s",
-                                operand, mode);
+        private void markLocation(LIRInstruction op, LIRFrameState info, ReferenceMap refMap) {
+            if (!info.hasDebugInfo()) {
+                info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
             }
+            info.updateUnion(refMap);
         }
 
-        protected boolean shouldProcessValue(Value operand) {
-            return (isRegister(operand) && attributes(asRegister(operand)).isAllocatable() || isStackSlot(operand)) && operand.getPlatformKind() != Kind.Illegal;
-        }
-    }
-
-    /**
-     * This method does the actual marking.
-     */
-    private void markLocation(LIRInstruction op, LIRFrameState info, ReferenceMap refMap) {
-        if (!info.hasDebugInfo()) {
-            info.initDebugInfo(frameMap, !op.destroysCallerSavedRegisters() || !frameMap.getRegisterConfig().areAllAllocatableRegistersCallerSaved());
+        /**
+         * Gets an object describing the attributes of a given register according to this register
+         * configuration.
+         *
+         * @see LinearScan#attributes
+         */
+        private RegisterAttributes attributes(Register reg) {
+            return registerAttributes[reg.number];
         }
-        info.updateUnion(refMap);
-    }
 
-    /**
-     * Gets an object describing the attributes of a given register according to this register
-     * configuration.
-     *
-     * @see LinearScan#attributes
-     */
-    private RegisterAttributes attributes(Register reg) {
-        return registerAttributes[reg.number];
     }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Range.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Range.java	Sat Feb 21 19:55:33 2015 +0100
@@ -50,7 +50,7 @@
 
     /**
      * Creates a new range.
-     * 
+     *
      * @param from the start of the range, inclusive
      * @param to the end of the range, exclusive
      * @param next link to the next range in a linked list
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
@@ -38,6 +39,7 @@
 import com.oracle.graal.lir.constopt.ConstantTree.Flags;
 import com.oracle.graal.lir.constopt.ConstantTree.NodeCost;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
 /**
@@ -45,27 +47,20 @@
  * 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 {
+public final class ConstantLoadOptimization extends PreAllocationOptimizationPhase {
 
     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
     }
 
-    public static void optimize(LIR lir, LIRGeneratorTool lirGen) {
-        new ConstantLoadOptimization(lir, lirGen).apply();
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+        new Optimization(lirGenRes.getLIR(), lirGen).apply();
     }
 
-    private LIR lir;
-    private LIRGeneratorTool lirGen;
-    private VariableMap<DefUseTree> map;
-    private BitSet phiConstants;
-    private BitSet defined;
-    private BlockMap<List<UseEntry>> blockMap;
-    private BlockMap<LIRInsertionBuffer> insertionBuffers;
-
     private static final DebugMetric constantsTotal = Debug.metric("ConstantLoadOptimization[total]");
     private static final DebugMetric phiConstantsSkipped = Debug.metric("ConstantLoadOptimization[PhisSkipped]");
     private static final DebugMetric singleUsageConstantsSkipped = Debug.metric("ConstantLoadOptimization[SingleUsageSkipped]");
@@ -73,275 +68,285 @@
     private static final DebugMetric materializeAtDefinitionSkipped = Debug.metric("ConstantLoadOptimization[MaterializeAtDefinitionSkipped]");
     private static final DebugMetric constantsOptimized = Debug.metric("ConstantLoadOptimization[optimized]");
 
-    private ConstantLoadOptimization(LIR lir, LIRGeneratorTool lirGen) {
-        this.lir = lir;
-        this.lirGen = lirGen;
-        this.map = new VariableMap<>();
-        this.phiConstants = new BitSet();
-        this.defined = new BitSet();
-        this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph());
-        this.blockMap = new BlockMap<>(lir.getControlFlowGraph());
-    }
+    private static final class Optimization {
+        private final LIR lir;
+        private final LIRGeneratorTool lirGen;
+        private final VariableMap<DefUseTree> map;
+        private final BitSet phiConstants;
+        private final BitSet defined;
+        private final BlockMap<List<UseEntry>> blockMap;
+        private final BlockMap<LIRInsertionBuffer> insertionBuffers;
+
+        private Optimization(LIR lir, LIRGeneratorTool lirGen) {
+            this.lir = lir;
+            this.lirGen = lirGen;
+            this.map = new VariableMap<>();
+            this.phiConstants = new BitSet();
+            this.defined = new BitSet();
+            this.insertionBuffers = new BlockMap<>(lir.getControlFlowGraph());
+            this.blockMap = new BlockMap<>(lir.getControlFlowGraph());
+        }
 
-    private void apply() {
-        try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) {
-            try (Scope s = Debug.scope("BuildDefUseTree")) {
-                // build DefUseTree
-                lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock);
-                // remove all with only one use
-                map.filter(t -> {
-                    if (t.usageCount() > 1) {
-                        return true;
-                    } else {
-                        singleUsageConstantsSkipped.increment();
-                        return false;
-                    }
-                });
-                // collect block map
-                map.forEach(tree -> tree.forEach(this::addUsageToBlockMap));
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
+        private void apply() {
+            try (Indent indent = Debug.logAndIndent("ConstantLoadOptimization")) {
+                try (Scope s = Debug.scope("BuildDefUseTree")) {
+                    // build DefUseTree
+                    lir.getControlFlowGraph().getBlocks().forEach(this::analyzeBlock);
+                    // remove all with only one use
+                    map.filter(t -> {
+                        if (t.usageCount() > 1) {
+                            return true;
+                        } else {
+                            singleUsageConstantsSkipped.increment();
+                            return false;
+                        }
+                    });
+                    // collect block map
+                    map.forEach(tree -> tree.forEach(this::addUsageToBlockMap));
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
 
-            try (Scope s = Debug.scope("BuildConstantTree")) {
-                // create ConstantTree
-                map.forEach(this::createConstantTree);
+                try (Scope s = Debug.scope("BuildConstantTree")) {
+                    // create ConstantTree
+                    map.forEach(this::createConstantTree);
 
-                // insert moves, delete null instructions and reset instruction ids
-                lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock);
+                    // insert moves, delete null instructions and reset instruction ids
+                    lir.getControlFlowGraph().getBlocks().forEach(this::rewriteBlock);
 
-                assert verifyStates();
-            } catch (Throwable e) {
-                throw Debug.handle(e);
+                    assert verifyStates();
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
             }
         }
-    }
 
-    private boolean verifyStates() {
-        map.forEach(this::verifyStateUsage);
-        return true;
-    }
+        private boolean verifyStates() {
+            map.forEach(this::verifyStateUsage);
+            return true;
+        }
+
+        private void verifyStateUsage(DefUseTree tree) {
+            Variable var = tree.getVariable();
+            ValueConsumer stateConsumer = new ValueConsumer() {
 
-    private void verifyStateUsage(DefUseTree tree) {
-        Variable var = tree.getVariable();
-        ValueConsumer stateConsumer = new ValueConsumer() {
-
-            @Override
-            public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
-                assert !operand.equals(var) : "constant usage through variable in frame state " + var;
-            }
-        };
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
-            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
-                // set instruction id to the index in the lir instruction list
-                inst.visitEachState(stateConsumer);
+                @Override
+                public void visitValue(Value operand, OperandMode mode, EnumSet<OperandFlag> flags) {
+                    assert !operand.equals(var) : "constant usage through variable in frame state " + var;
+                }
+            };
+            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+                for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                    // set instruction id to the index in the lir instruction list
+                    inst.visitEachState(stateConsumer);
+                }
             }
         }
-    }
 
-    private static boolean isConstantLoad(LIRInstruction inst) {
-        if (!(inst instanceof MoveOp)) {
-            return false;
+        private static boolean isConstantLoad(LIRInstruction inst) {
+            if (!(inst instanceof MoveOp)) {
+                return false;
+            }
+            MoveOp move = (MoveOp) inst;
+            return isConstant(move.getInput()) && isVariable(move.getResult());
         }
-        MoveOp move = (MoveOp) inst;
-        return isConstant(move.getInput()) && isVariable(move.getResult());
-    }
 
-    private void addUsageToBlockMap(UseEntry entry) {
-        AbstractBlock<?> block = entry.getBlock();
-        List<UseEntry> list = blockMap.get(block);
-        if (list == null) {
-            list = new ArrayList<>();
-            blockMap.put(block, list);
+        private void addUsageToBlockMap(UseEntry entry) {
+            AbstractBlock<?> block = entry.getBlock();
+            List<UseEntry> list = blockMap.get(block);
+            if (list == null) {
+                list = new ArrayList<>();
+                blockMap.put(block, list);
+            }
+            list.add(entry);
         }
-        list.add(entry);
-    }
 
-    /**
-     * Collects def-use information for a {@code block}.
-     */
-    private void analyzeBlock(AbstractBlock<?> block) {
-        try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
+        /**
+         * Collects def-use information for a {@code block}.
+         */
+        private void analyzeBlock(AbstractBlock<?> block) {
+            try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
+
+                InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
 
-            InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
-                if (isVariable(value)) {
-                    Variable var = (Variable) value;
-
-                    if (!phiConstants.get(var.index)) {
-                        if (!defined.get(var.index)) {
-                            defined.set(var.index);
-                            if (isConstantLoad(instruction)) {
-                                Debug.log("constant load: %s", instruction);
-                                map.put(var, new DefUseTree(instruction, block));
-                                constantsTotal.increment();
+                        if (!phiConstants.get(var.index)) {
+                            if (!defined.get(var.index)) {
+                                defined.set(var.index);
+                                if (isConstantLoad(instruction)) {
+                                    Debug.log("constant load: %s", instruction);
+                                    map.put(var, new DefUseTree(instruction, block));
+                                    constantsTotal.increment();
+                                }
+                            } else {
+                                // Variable is redefined, this only happens for constant loads
+                                // introduced by phi resolution -> ignore.
+                                DefUseTree removed = map.remove(var);
+                                if (removed != null) {
+                                    phiConstantsSkipped.increment();
+                                }
+                                phiConstants.set(var.index);
+                                Debug.log(3, "Removing phi variable: %s", var);
                             }
                         } else {
-                            // Variable is redefined, this only happens for constant loads
-                            // introduced by phi resolution -> ignore.
-                            DefUseTree removed = map.remove(var);
-                            if (removed != null) {
-                                phiConstantsSkipped.increment();
-                            }
-                            phiConstants.set(var.index);
-                            Debug.log(3, "Removing phi variable: %s", var);
+                            assert defined.get(var.index) : "phi but not defined? " + var;
                         }
-                    } else {
-                        assert defined.get(var.index) : "phi but not defined? " + var;
                     }
-                }
-            };
+                };
 
-            ValuePositionProcedure useProcedure = (instruction, position) -> {
-                Value value = position.get(instruction);
-                if (isVariable(value)) {
-                    Variable var = (Variable) value;
-                    if (!phiConstants.get(var.index)) {
-                        DefUseTree tree = map.get(var);
-                        if (tree != null) {
-                            tree.addUsage(block, instruction, position);
-                            Debug.log("usage of %s : %s", var, instruction);
+                ValuePositionProcedure useProcedure = (instruction, position) -> {
+                    Value value = position.get(instruction);
+                    if (isVariable(value)) {
+                        Variable var = (Variable) value;
+                        if (!phiConstants.get(var.index)) {
+                            DefUseTree tree = map.get(var);
+                            if (tree != null) {
+                                tree.addUsage(block, instruction, position);
+                                Debug.log("usage of %s : %s", var, instruction);
+                            }
                         }
                     }
-                }
-            };
+                };
 
-            int opId = 0;
-            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
-                // set instruction id to the index in the lir instruction list
-                inst.setId(opId++);
-                inst.visitEachOutput(loadConsumer);
-                inst.forEachInputPos(useProcedure);
-                inst.forEachAlivePos(useProcedure);
+                int opId = 0;
+                for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                    // set instruction id to the index in the lir instruction list
+                    inst.setId(opId++);
+                    inst.visitEachOutput(loadConsumer);
+                    inst.forEachInputPos(useProcedure);
+                    inst.forEachAlivePos(useProcedure);
 
+                }
             }
         }
-    }
-
-    /**
-     * Creates the dominator tree and searches for an solution.
-     */
-    private void createConstantTree(DefUseTree tree) {
-        ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
-        constTree.set(Flags.SUBTREE, tree.getBlock());
-        tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
-
-        if (constTree.get(Flags.USAGE, tree.getBlock())) {
-            // usage in the definition block -> no optimization
-            usageAtDefinitionSkipped.increment();
-            return;
-        }
 
-        constTree.markBlocks();
+        /**
+         * Creates the dominator tree and searches for an solution.
+         */
+        private void createConstantTree(DefUseTree tree) {
+            ConstantTree constTree = new ConstantTree(lir.getControlFlowGraph(), tree);
+            constTree.set(Flags.SUBTREE, tree.getBlock());
+            tree.forEach(u -> constTree.set(Flags.USAGE, u.getBlock()));
 
-        NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock());
-        int usageCount = cost.getUsages().size();
-        assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
-
-        if (Debug.isLogEnabled()) {
-            try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
-                Debug.log("Usages result: %s", cost);
+            if (constTree.get(Flags.USAGE, tree.getBlock())) {
+                // usage in the definition block -> no optimization
+                usageAtDefinitionSkipped.increment();
+                return;
             }
 
+            constTree.markBlocks();
+
+            NodeCost cost = ConstantTreeAnalyzer.analyze(constTree, tree.getBlock());
+            int usageCount = cost.getUsages().size();
+            assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount();
+
+            if (Debug.isLogEnabled()) {
+                try (Indent i = Debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) {
+                    Debug.log("Usages result: %s", cost);
+                }
+
+            }
+
+            if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
+                try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
+                    // mark original load for removal
+                    deleteInstruction(tree);
+                    constantsOptimized.increment();
+
+                    // collect result
+                    createLoads(tree, constTree, tree.getBlock());
+
+                } catch (Throwable e) {
+                    throw Debug.handle(e);
+                }
+            } else {
+                // no better solution found
+                materializeAtDefinitionSkipped.increment();
+            }
+            Debug.dump(constTree, "ConstantTree for " + tree.getVariable());
         }
 
-        if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) {
-            try (Scope s = Debug.scope("CLOmodify", constTree); Indent i = Debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) {
-                // mark original load for removal
-                deleteInstruction(tree);
-                constantsOptimized.increment();
-
-                // collect result
-                createLoads(tree, constTree, tree.getBlock());
-
-            } catch (Throwable e) {
-                throw Debug.handle(e);
-            }
-        } else {
-            // no better solution found
-            materializeAtDefinitionSkipped.increment();
-        }
-        Debug.dump(constTree, "ConstantTree for " + tree.getVariable());
-    }
-
-    private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) {
-        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
-        worklist.add(startBlock);
-        while (!worklist.isEmpty()) {
-            AbstractBlock<?> block = worklist.pollLast();
-            if (constTree.get(Flags.CANDIDATE, block)) {
-                constTree.set(Flags.MATERIALIZE, block);
-                // create and insert load
-                insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages());
-            } else {
-                for (AbstractBlock<?> dominated : block.getDominated()) {
-                    if (constTree.isMarked(dominated)) {
-                        worklist.addLast(dominated);
+        private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) {
+            Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+            worklist.add(startBlock);
+            while (!worklist.isEmpty()) {
+                AbstractBlock<?> block = worklist.pollLast();
+                if (constTree.get(Flags.CANDIDATE, block)) {
+                    constTree.set(Flags.MATERIALIZE, block);
+                    // create and insert load
+                    insertLoad(tree.getConstant(), tree.getVariable().getLIRKind(), block, constTree.getCost(block).getUsages());
+                } else {
+                    for (AbstractBlock<?> dominated : block.getDominated()) {
+                        if (constTree.isMarked(dominated)) {
+                            worklist.addLast(dominated);
+                        }
                     }
                 }
             }
         }
-    }
 
-    private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) {
-        assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages);
-        // create variable
-        Variable variable = lirGen.newVariable(kind);
-        // create move
-        LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant);
-        // insert instruction
-        getInsertionBuffer(block).append(1, move);
-        Debug.log("new move (%s) and inserted in block %s", move, block);
-        // update usages
-        for (UseEntry u : usages) {
-            u.getPosition().set(u.getInstruction(), variable);
-            Debug.log("patched instruction %s", u.getInstruction());
-        }
-    }
-
-    /**
-     * Inserts the constant loads created in {@link #createConstantTree} and deletes the original
-     * definition.
-     */
-    private void rewriteBlock(AbstractBlock<?> block) {
-        // insert moves
-        LIRInsertionBuffer buffer = insertionBuffers.get(block);
-        if (buffer != null) {
-            assert buffer.initialized() : "not initialized?";
-            buffer.finish();
+        private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) {
+            assert usages != null && usages.size() > 0 : String.format("No usages %s %s %s", constant, block, usages);
+            // create variable
+            Variable variable = lirGen.newVariable(kind);
+            // create move
+            LIRInstruction move = lir.getSpillMoveFactory().createMove(variable, constant);
+            // insert instruction
+            getInsertionBuffer(block).append(1, move);
+            Debug.log("new move (%s) and inserted in block %s", move, block);
+            // update usages
+            for (UseEntry u : usages) {
+                u.getPosition().set(u.getInstruction(), variable);
+                Debug.log("patched instruction %s", u.getInstruction());
+            }
         }
 
-        // delete instructions
-        List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-        boolean hasDead = false;
-        for (LIRInstruction inst : instructions) {
-            if (inst == null) {
-                hasDead = true;
-            } else {
-                inst.setId(-1);
+        /**
+         * Inserts the constant loads created in {@link #createConstantTree} and deletes the
+         * original definition.
+         */
+        private void rewriteBlock(AbstractBlock<?> block) {
+            // insert moves
+            LIRInsertionBuffer buffer = insertionBuffers.get(block);
+            if (buffer != null) {
+                assert buffer.initialized() : "not initialized?";
+                buffer.finish();
+            }
+
+            // delete instructions
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            boolean hasDead = false;
+            for (LIRInstruction inst : instructions) {
+                if (inst == null) {
+                    hasDead = true;
+                } else {
+                    inst.setId(-1);
+                }
+            }
+            if (hasDead) {
+                // Remove null values from the list.
+                instructions.removeAll(Collections.singleton(null));
             }
         }
-        if (hasDead) {
-            // Remove null values from the list.
-            instructions.removeAll(Collections.singleton(null));
+
+        private void deleteInstruction(DefUseTree tree) {
+            AbstractBlock<?> block = tree.getBlock();
+            LIRInstruction instruction = tree.getInstruction();
+            Debug.log("deleting instruction %s from block %s", instruction, block);
+            lir.getLIRforBlock(block).set(instruction.id(), null);
+        }
+
+        private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) {
+            LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
+            if (insertionBuffer == null) {
+                insertionBuffer = new LIRInsertionBuffer();
+                insertionBuffers.put(block, insertionBuffer);
+                assert !insertionBuffer.initialized() : "already initialized?";
+                List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+                insertionBuffer.init(instructions);
+            }
+            return insertionBuffer;
         }
     }
-
-    private void deleteInstruction(DefUseTree tree) {
-        AbstractBlock<?> block = tree.getBlock();
-        LIRInstruction instruction = tree.getInstruction();
-        Debug.log("deleting instruction %s from block %s", instruction, block);
-        lir.getLIRforBlock(block).set(instruction.id(), null);
-    }
-
-    private LIRInsertionBuffer getInsertionBuffer(AbstractBlock<?> block) {
-        LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
-        if (insertionBuffer == null) {
-            insertionBuffer = new LIRInsertionBuffer();
-            insertionBuffers.put(block, insertionBuffer);
-            assert !insertionBuffer.initialized() : "already initialized?";
-            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
-            insertionBuffer.init(instructions);
-        }
-        return insertionBuffer;
-    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -71,14 +71,6 @@
         this.cc = cc;
     }
 
-    /**
-     * Returns true if the redundant move elimination optimization should be done after register
-     * allocation.
-     */
-    public boolean canEliminateRedundantMoves() {
-        return true;
-    }
-
     @Override
     public TargetDescription target() {
         return getCodeCache().getTarget();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Sat Feb 21 19:55:33 2015 +0100
@@ -139,12 +139,6 @@
     Value loadNonConst(Value value);
 
     /**
-     * Returns true if the redundant move elimination optimization should be done after register
-     * allocation.
-     */
-    boolean canEliminateRedundantMoves();
-
-    /**
      * Determines if only oop maps are required for the code generated from the LIR.
      */
     boolean needOnlyOopMaps();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java	Sat Feb 21 19:55:33 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 AllocationPhase extends LIRPhase<AllocationPhase.AllocationContext> {
+
+    public static final class AllocationContext {
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext 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/AllocationStage.java	Sat Feb 21 19:55:33 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.AllocationPhase.*;
+import com.oracle.graal.lir.stackslotalloc.*;
+
+public class AllocationStage extends LIRPhaseSuite<AllocationContext> {
+    public AllocationStage() {
+        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/LIRPhase.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
+import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
+import com.oracle.graal.lir.phases.AllocationPhase.AllocationContext;
+
+public class LIRSuites {
+
+    private final LIRPhaseSuite<PreAllocationOptimizationContext> preAllocOptStage;
+    private final LIRPhaseSuite<AllocationContext> allocStage;
+    private final LIRPhaseSuite<PostAllocationOptimizationContext> postAllocStage;
+
+    public LIRSuites(LIRPhaseSuite<PreAllocationOptimizationContext> preAllocOptStage, LIRPhaseSuite<AllocationContext> allocStage, LIRPhaseSuite<PostAllocationOptimizationContext> postAllocStage) {
+        this.preAllocOptStage = preAllocOptStage;
+        this.allocStage = allocStage;
+        this.postAllocStage = postAllocStage;
+    }
+
+    /**
+     * {@link PreAllocationOptimizationPhase}s are executed between {@link LIR} generation and
+     * register allocation.
+     * <p>
+     * {@link PreAllocationOptimizationPhase Implementers} can create new
+     * {@link LIRGeneratorTool#newVariable variables}, {@link LIRGenerationResult#getFrameMap stack
+     * slots} and {@link LIRGenerationResult#getFrameMapBuilder virtual stack slots}.
+     */
+    public LIRPhaseSuite<PreAllocationOptimizationContext> getPreAllocationOptimizationStage() {
+        return preAllocOptStage;
+    }
+
+    /**
+     * {@link AllocationPhase}s are responsible for register allocation and translating
+     * {@link VirtualStackSlot}s into {@link StackSlot}s.
+     * <p>
+     * After the {@link AllocationStage} there should be no more {@link Variable}s and
+     * {@link VirtualStackSlot}s.
+     */
+    public LIRPhaseSuite<AllocationContext> getAllocationStage() {
+        return allocStage;
+    }
+
+    /**
+     * {@link PostAllocationOptimizationPhase}s are executed after register allocation and before
+     * machine code generation.
+     * <p>
+     * A {@link PostAllocationOptimizationPhase} must not introduce new {@link Variable}s,
+     * {@link VirtualStackSlot}s or {@link StackSlot}s.
+     */
+    public LIRPhaseSuite<PostAllocationOptimizationContext> getPostAllocationOptimizationStage() {
+        return postAllocStage;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/PostAllocationOptimizationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,44 @@
+/*
+ * 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 PostAllocationOptimizationPhase extends LIRPhase<PostAllocationOptimizationPhase.PostAllocationOptimizationContext> {
+
+    public static final class PostAllocationOptimizationContext {
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    PostAllocationOptimizationContext 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/PostAllocationOptimizationStage.java	Sat Feb 21 19:55:33 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.PostAllocationOptimizationPhase.*;
+import com.oracle.graal.options.*;
+
+public class PostAllocationOptimizationStage extends LIRPhaseSuite<PostAllocationOptimizationContext> {
+    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 PostAllocationOptimizationStage() {
+        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/PreAllocationOptimizationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,50 @@
+/*
+ * 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 PreAllocationOptimizationPhase extends LIRPhase<PreAllocationOptimizationPhase.PreAllocationOptimizationContext> {
+
+    public static final class PreAllocationOptimizationContext {
+        private final LIRGeneratorTool lirGen;
+
+        public PreAllocationOptimizationContext(LIRGeneratorTool lirGen) {
+            this.lirGen = lirGen;
+        }
+
+    }
+
+    @Override
+    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    PreAllocationOptimizationContext 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/PreAllocationOptimizationStage.java	Sat Feb 21 19:55:33 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.PreAllocationOptimizationPhase.*;
+
+public class PreAllocationOptimizationStage extends LIRPhaseSuite<PreAllocationOptimizationContext> {
+    public PreAllocationOptimizationStage() {
+        if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue()) {
+            appendPhase(new ConstantLoadOptimization());
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,6 +38,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
 /**
@@ -50,12 +51,12 @@
  * {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content
  * destroyed.
  */
-public final class LSStackSlotAllocator implements StackSlotAllocator {
+public final class LSStackSlotAllocator extends AllocationPhase 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
     }
 
@@ -66,6 +67,11 @@
     private static final DebugTimer AllocateSlotsTimer = Debug.timer("LSStackSlotAllocator[AllocateSlots]");
     private static final DebugTimer AssignSlotsTimer = Debug.timer("LSStackSlotAllocator[AssignSlots]");
 
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        lirGenRes.buildFrameMap(this);
+    }
+
     public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
         try (TimerCloseable t = MainTimer.start()) {
             new Allocator(res.getLIR(), builder).allocate();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,16 +24,24 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.*;
+import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
 
-public class SimpleStackSlotAllocator implements StackSlotAllocator {
+public class SimpleStackSlotAllocator extends AllocationPhase implements StackSlotAllocator {
+
+    @Override
+    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+        lirGenRes.buildFrameMap(this);
+    }
 
     public void allocateStackSlots(FrameMapBuilderTool builder, LIRGenerationResult res) {
         StackSlot[] mapping = new StackSlot[builder.getNumberOfStackSlots()];
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Sat Feb 21 19:55:33 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/LoopFragment.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Sat Feb 21 19:55:33 2015 +0100
@@ -312,9 +312,9 @@
             if (newEarlyExit == null) {
                 continue;
             }
-            AbstractMergeNode merge = graph.add(new MergeNode());
-            AbstractEndNode originalEnd = graph.add(new EndNode());
-            AbstractEndNode newEnd = graph.add(new EndNode());
+            MergeNode merge = graph.add(new MergeNode());
+            EndNode originalEnd = graph.add(new EndNode());
+            EndNode newEnd = graph.add(new EndNode());
             merge.addForwardEnd(originalEnd);
             merge.addForwardEnd(newEnd);
             loopEarlyExit.setNext(originalEnd);
@@ -332,7 +332,7 @@
                  * VirtualState nodes contained in the old exit's state may be shared by other
                  * dominated VirtualStates. Those dominated virtual states need to see the
                  * proxy->phi update that are applied below.
-                 * 
+                 *
                  * We now update the original fragment's nodes accordingly:
                  */
                 originalExitState.applyToVirtual(node -> original.nodes.clearAndGrow(node));
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Sat Feb 21 19:55:33 2015 +0100
@@ -293,14 +293,14 @@
 
     private AbstractBeginNode mergeEnds() {
         assert isDuplicate();
-        List<AbstractEndNode> endsToMerge = new LinkedList<>();
+        List<EndNode> endsToMerge = new LinkedList<>();
         // map peel exits to the corresponding loop exits
         Map<AbstractEndNode, LoopEndNode> reverseEnds = CollectionsFactory.newMap();
         LoopBeginNode loopBegin = original().loop().loopBegin();
         for (LoopEndNode le : loopBegin.loopEnds()) {
             AbstractEndNode duplicate = getDuplicatedNode(le);
             if (duplicate != null) {
-                endsToMerge.add(duplicate);
+                endsToMerge.add((EndNode) duplicate);
                 reverseEnds.put(duplicate, le);
             }
         }
@@ -323,7 +323,7 @@
                 duplicateState = state.duplicateWithVirtualState();
                 newExitMerge.setStateAfter(duplicateState);
             }
-            for (AbstractEndNode end : endsToMerge) {
+            for (EndNode end : endsToMerge) {
                 newExitMerge.addForwardEnd(end);
             }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Sat Feb 21 19:55:33 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");
             }
         }
@@ -77,6 +68,8 @@
         LoopFragmentWhole originalLoop = loop.whole();
         StructuredGraph graph = firstNode.graph();
 
+        loop.loopBegin().incrementUnswitches();
+
         // create new control split out of loop
         ControlSplitNode newControlSplit = (ControlSplitNode) firstNode.copyWithInputs();
         originalLoop.entryPoint().replaceAtPredecessor(newControlSplit);
@@ -121,27 +114,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Sat Feb 21 19:55:33 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) {
@@ -42,7 +43,7 @@
             do {
                 unswitched = false;
                 final LoopsData dataUnswitch = new LoopsData(graph);
-                for (LoopEx loop : dataUnswitch.loops()) {
+                for (LoopEx loop : dataUnswitch.outerFirst()) {
                     if (LoopPolicies.shouldTryUnswitch(loop)) {
                         List<ControlSplitNode> controlSplits = LoopTransformations.findUnswitchable(loop);
                         if (controlSplits != null) {
@@ -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/GraphNodeProcessor.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Sat Feb 21 19:55:33 2015 +0100
@@ -133,6 +133,18 @@
                     // NodeInfo.class.getSimpleName());
                     // continue;
                 }
+                boolean found = false;
+                for (Element e : typeElement.getEnclosedElements()) {
+                    if (e.getKind() == ElementKind.FIELD) {
+                        if (e.getSimpleName().toString().equals("TYPE")) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+                if (!found) {
+                    errorMessage(element, "%s annotated class must have a field named TYPE", NodeInfo.class.getSimpleName());
+                }
 
                 if (!typeElement.equals(verifier.Node) && !modifiers.contains(Modifier.ABSTRACT)) {
                     verifier.verify(typeElement);
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeVerifier.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/IntegerStampTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/LoopPhiCanonicalizerTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes.test/src/com/oracle/graal/nodes/test/NegateNodeCanonicalizationTest.java	Sat Feb 21 19:55:33 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/AbstractBeginNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,12 +38,14 @@
 @NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
 public abstract class AbstractBeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, GuardingNode, AnchoringNode, IterableNodeType {
 
-    public AbstractBeginNode() {
-        super(StampFactory.forVoid());
+    public static final NodeClass<AbstractBeginNode> TYPE = NodeClass.create(AbstractBeginNode.class);
+
+    protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c) {
+        this(c, StampFactory.forVoid());
     }
 
-    public AbstractBeginNode(Stamp stamp) {
-        super(stamp);
+    protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,14 +36,11 @@
 @NodeInfo
 public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode.DeoptBefore {
 
+    public static final NodeClass<AbstractDeoptimizeNode> TYPE = NodeClass.create(AbstractDeoptimizeNode.class);
     @OptionalInput(InputType.State) FrameState stateBefore;
 
-    public AbstractDeoptimizeNode() {
-        super(StampFactory.forVoid());
-    }
-
-    public AbstractDeoptimizeNode(FrameState stateBefore) {
-        super(StampFactory.forVoid());
+    protected AbstractDeoptimizeNode(NodeClass<? extends AbstractDeoptimizeNode> c, FrameState stateBefore) {
+        super(c, StampFactory.forVoid());
         this.stateBefore = stateBefore;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,8 +32,10 @@
 @NodeInfo
 public abstract class AbstractEndNode extends FixedNode implements IterableNodeType, LIRLowerable {
 
-    protected AbstractEndNode() {
-        super(StampFactory.forVoid());
+    public static final NodeClass<AbstractEndNode> TYPE = NodeClass.create(AbstractEndNode.class);
+
+    protected AbstractEndNode(NodeClass<? extends AbstractEndNode> c) {
+        super(c, StampFactory.forVoid());
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.extended.*;
@@ -32,6 +33,7 @@
 @NodeInfo
 public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode {
 
+    public static final NodeClass<AbstractFixedGuardNode> TYPE = NodeClass.create(AbstractFixedGuardNode.class);
     @Input(InputType.Condition) protected LogicNode condition;
     protected final DeoptimizationReason reason;
     protected final DeoptimizationAction action;
@@ -46,8 +48,8 @@
         condition = x;
     }
 
-    protected AbstractFixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
-        super(StampFactory.forVoid());
+    protected AbstractFixedGuardNode(NodeClass<? extends AbstractFixedGuardNode> c, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
+        super(c, StampFactory.forVoid());
         this.action = action;
         this.negated = negated;
         this.condition = condition;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,16 +23,18 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
 
 @NodeInfo
 public abstract class AbstractLocalNode extends FloatingNode {
 
+    public static final NodeClass<AbstractLocalNode> TYPE = NodeClass.create(AbstractLocalNode.class);
     protected final int index;
 
-    public AbstractLocalNode(int index, Stamp stamp) {
-        super(stamp);
+    protected AbstractLocalNode(NodeClass<? extends AbstractLocalNode> c, int index, Stamp stamp) {
+        super(c, stamp);
         this.index = index;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 
@@ -32,11 +33,13 @@
 @NodeInfo
 public abstract class AbstractMemoryCheckpoint extends AbstractStateSplit implements MemoryCheckpoint {
 
-    protected AbstractMemoryCheckpoint(Stamp stamp) {
-        super(stamp);
+    public static final NodeClass<AbstractMemoryCheckpoint> TYPE = NodeClass.create(AbstractMemoryCheckpoint.class);
+
+    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp) {
+        this(c, stamp, null);
     }
 
-    protected AbstractMemoryCheckpoint(Stamp stamp, FrameState stateAfter) {
-        super(stamp, stateAfter);
+    protected AbstractMemoryCheckpoint(NodeClass<? extends AbstractMemoryCheckpoint> c, Stamp stamp, FrameState stateAfter) {
+        super(c, stamp, stateAfter);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMergeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMergeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,21 +39,24 @@
  */
 @NodeInfo(allowedUsageTypes = {InputType.Association})
 public abstract class AbstractMergeNode extends BeginStateSplitNode implements IterableNodeType, LIRLowerable {
-    protected AbstractMergeNode() {
+    public static final NodeClass<AbstractMergeNode> TYPE = NodeClass.create(AbstractMergeNode.class);
+
+    protected AbstractMergeNode(NodeClass<? extends AbstractMergeNode> c) {
+        super(c);
     }
 
-    @Input(InputType.Association) protected NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
+    @Input(InputType.Association) protected NodeInputList<EndNode> ends = new NodeInputList<>(this);
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         gen.visitMerge(this);
     }
 
-    public int forwardEndIndex(AbstractEndNode end) {
+    public int forwardEndIndex(EndNode end) {
         return ends.indexOf(end);
     }
 
-    public void addForwardEnd(AbstractEndNode end) {
+    public void addForwardEnd(EndNode end) {
         ends.add(end);
     }
 
@@ -61,12 +64,12 @@
         return ends.size();
     }
 
-    public AbstractEndNode forwardEndAt(int index) {
+    public EndNode forwardEndAt(int index) {
         return ends.get(index);
     }
 
     @Override
-    public NodeIterable<AbstractEndNode> cfgPredecessors() {
+    public NodeIterable<EndNode> cfgPredecessors() {
         return ends;
     }
 
@@ -110,7 +113,7 @@
         ends.clear();
     }
 
-    public NodeInputList<AbstractEndNode> forwardEnds() {
+    public NodeInputList<EndNode> forwardEnds() {
         return ends;
     }
 
@@ -119,7 +122,7 @@
     }
 
     public int phiPredecessorIndex(AbstractEndNode pred) {
-        return forwardEndIndex(pred);
+        return forwardEndIndex((EndNode) pred);
     }
 
     public AbstractEndNode phiPredecessorAt(int index) {
@@ -173,8 +176,9 @@
                 if (merge instanceof LoopBeginNode) {
                     newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
                 } else {
-                    newEnd = graph().add(new EndNode());
-                    merge.addForwardEnd(newEnd);
+                    EndNode tmpEnd = graph().add(new EndNode());
+                    merge.addForwardEnd(tmpEnd);
+                    newEnd = tmpEnd;
                 }
                 for (PhiNode phi : merge.phis()) {
                     ValueNode v = phi.valueAt(origLoopEnd);
@@ -210,8 +214,8 @@
             }
 
             ValuePhiNode returnValuePhi = returnNode.result() == null || !isPhiAtMerge(returnNode.result()) ? null : (ValuePhiNode) returnNode.result();
-            List<AbstractEndNode> endNodes = forwardEnds().snapshot();
-            for (AbstractEndNode end : endNodes) {
+            List<EndNode> endNodes = forwardEnds().snapshot();
+            for (EndNode end : endNodes) {
                 ReturnNode newReturn = graph().add(new ReturnNode(returnValuePhi == null ? returnNode.result() : returnValuePhi.valueAt(end)));
                 if (tool != null) {
                     tool.addToWorkList(end.predecessor());
@@ -219,7 +223,7 @@
                 end.replaceAtPredecessor(newReturn);
             }
             GraphUtil.killCFG(this);
-            for (AbstractEndNode end : endNodes) {
+            for (EndNode end : endNodes) {
                 end.safeDelete();
             }
             for (PhiNode phi : phis) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 /**
@@ -31,6 +32,7 @@
 @NodeInfo
 public abstract class AbstractStateSplit extends FixedWithNextNode implements StateSplit {
 
+    public static final NodeClass<AbstractStateSplit> TYPE = NodeClass.create(AbstractStateSplit.class);
     @OptionalInput(InputType.State) protected FrameState stateAfter;
 
     public FrameState stateAfter() {
@@ -47,12 +49,12 @@
         return true;
     }
 
-    public AbstractStateSplit(Stamp stamp) {
-        super(stamp);
+    protected AbstractStateSplit(NodeClass<? extends AbstractStateSplit> c, Stamp stamp) {
+        this(c, stamp, null);
     }
 
-    public AbstractStateSplit(Stamp stamp, FrameState stateAfter) {
-        super(stamp);
+    protected AbstractStateSplit(NodeClass<? extends AbstractStateSplit> c, Stamp stamp, FrameState stateAfter) {
+        super(c, stamp);
         this.stateAfter = stateAfter;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,17 +23,20 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
 public final class BeginNode extends AbstractBeginNode {
 
+    public static final NodeClass<BeginNode> TYPE = NodeClass.create(BeginNode.class);
+
     public BeginNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     public BeginNode(Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
     }
 
     public static AbstractBeginNode begin(FixedNode with) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 /**
@@ -35,13 +36,15 @@
 @NodeInfo
 public abstract class BeginStateSplitNode extends AbstractBeginNode implements StateSplit {
 
+    public static final NodeClass<BeginStateSplitNode> TYPE = NodeClass.create(BeginStateSplitNode.class);
     @OptionalInput(InputType.State) protected FrameState stateAfter;
 
-    public BeginStateSplitNode() {
+    protected BeginStateSplitNode(NodeClass<? extends BeginStateSplitNode> c) {
+        super(c);
     }
 
-    protected BeginStateSplitNode(Stamp stamp) {
-        super(stamp);
+    protected BeginStateSplitNode(NodeClass<? extends BeginStateSplitNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     public FrameState stateAfter() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
@@ -29,6 +30,7 @@
 @NodeInfo
 public abstract class BinaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable.Binary<ValueNode> {
 
+    public static final NodeClass<BinaryOpLogicNode> TYPE = NodeClass.create(BinaryOpLogicNode.class);
     @Input protected ValueNode x;
     @Input protected ValueNode y;
 
@@ -40,7 +42,8 @@
         return y;
     }
 
-    public BinaryOpLogicNode(ValueNode x, ValueNode y) {
+    public BinaryOpLogicNode(NodeClass<? extends BinaryOpLogicNode> c, ValueNode x, ValueNode y) {
+        super(c);
         assert x != null && y != null && x.getKind() == y.getKind();
         this.x = x;
         this.y = y;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -48,10 +48,11 @@
 @NodeInfo
 public final class BreakpointNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<BreakpointNode> TYPE = NodeClass.create(BreakpointNode.class);
     @Input NodeInputList<ValueNode> arguments;
 
     public BreakpointNode(ValueNode[] arguments) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.arguments = new NodeInputList<>(this, arguments);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,6 +32,8 @@
 
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
 public abstract class CallTargetNode extends ValueNode implements LIRLowerable {
+    public static final NodeClass<CallTargetNode> TYPE = NodeClass.create(CallTargetNode.class);
+
     public enum InvokeKind {
         Interface(false),
         Special(true),
@@ -65,15 +67,15 @@
     protected ResolvedJavaMethod targetMethod;
     protected InvokeKind invokeKind;
 
-    public CallTargetNode(ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
-        super(StampFactory.forVoid());
+    protected CallTargetNode(NodeClass<? extends CallTargetNode> c, ValueNode[] arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
+        super(c, StampFactory.forVoid());
         this.targetMethod = targetMethod;
         this.invokeKind = invokeKind;
         this.arguments = new NodeInputList<>(this, arguments);
     }
 
-    public CallTargetNode(List<ValueNode> arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
-        super(StampFactory.forVoid());
+    protected CallTargetNode(NodeClass<? extends CallTargetNode> c, List<ValueNode> arguments, ResolvedJavaMethod targetMethod, InvokeKind invokeKind) {
+        super(c, StampFactory.forVoid());
         this.targetMethod = targetMethod;
         this.invokeKind = invokeKind;
         this.arguments = new NodeInputList<>(this, arguments);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,6 +32,7 @@
 @NodeInfo(nameTemplate = "ConditionAnchor(!={p#negated})", allowedUsageTypes = {InputType.Guard})
 public final class ConditionAnchorNode extends FixedWithNextNode implements Canonicalizable.Unary<Node>, Lowerable, GuardingNode {
 
+    public static final NodeClass<ConditionAnchorNode> TYPE = NodeClass.create(ConditionAnchorNode.class);
     @Input(InputType.Condition) LogicNode condition;
     protected boolean negated;
 
@@ -40,7 +41,7 @@
     }
 
     public ConditionAnchorNode(LogicNode condition, boolean negated) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.negated = negated;
         this.condition = condition;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -41,6 +41,7 @@
 @NodeInfo(shortName = "Const", nameTemplate = "Const({p#rawvalue})")
 public final class ConstantNode extends FloatingNode implements LIRLowerable {
 
+    public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
     private static final DebugMetric ConstantNodes = Debug.metric("ConstantNodes");
 
     protected final Constant value;
@@ -56,7 +57,7 @@
      * @param value the constant
      */
     public ConstantNode(Constant value, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         assert stamp != null && isCompatible(value, stamp);
         this.value = value;
         ConstantNodes.increment();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,12 +23,14 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
 public abstract class ControlSinkNode extends FixedNode {
+    public static final NodeClass<ControlSinkNode> TYPE = NodeClass.create(ControlSinkNode.class);
 
-    public ControlSinkNode(Stamp stamp) {
-        super(stamp);
+    protected ControlSinkNode(NodeClass<? extends ControlSinkNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,9 +32,10 @@
  */
 @NodeInfo
 public abstract class ControlSplitNode extends FixedNode implements IterableNodeType {
+    public static final NodeClass<ControlSplitNode> TYPE = NodeClass.create(ControlSplitNode.class);
 
-    public ControlSplitNode(Stamp stamp) {
-        super(stamp);
+    protected ControlSplitNode(NodeClass<? extends ControlSplitNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     public abstract double probability(AbstractBeginNode successor);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,12 +23,14 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
 public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
 
+    public static final NodeClass<DeoptimizeNode> TYPE = NodeClass.create(DeoptimizeNode.class);
     protected final DeoptimizationAction action;
     protected final DeoptimizationReason reason;
     protected final int debugId;
@@ -39,7 +41,7 @@
     }
 
     public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason, int debugId, JavaConstant speculation, FrameState stateBefore) {
-        super(stateBefore);
+        super(TYPE, stateBefore);
         assert action != null;
         assert reason != null;
         assert speculation.getKind() == Kind.Object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,19 +23,21 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
 public abstract class DeoptimizingFixedWithNextNode extends FixedWithNextNode implements DeoptimizingNode.DeoptBefore {
 
+    public static final NodeClass<DeoptimizingFixedWithNextNode> TYPE = NodeClass.create(DeoptimizingFixedWithNextNode.class);
     @OptionalInput(InputType.State) protected FrameState stateBefore;
 
-    public DeoptimizingFixedWithNextNode(Stamp stamp) {
-        super(stamp);
+    protected DeoptimizingFixedWithNextNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
-    public DeoptimizingFixedWithNextNode(Stamp stamp, FrameState stateBefore) {
-        super(stamp);
+    protected DeoptimizingFixedWithNextNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, Stamp stamp, FrameState stateBefore) {
+        super(c, stamp);
         this.stateBefore = stateBefore;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,13 +27,17 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public class DirectCallTargetNode extends LoweredCallTargetNode {
+public abstract class DirectCallTargetNode extends LoweredCallTargetNode {
+
+    public static final NodeClass<DirectCallTargetNode> TYPE = NodeClass.create(DirectCallTargetNode.class);
 
-    public DirectCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
-        super(arguments, returnStamp, signature, target, callType, invokeKind);
+    protected DirectCallTargetNode(NodeClass<? extends DirectCallTargetNode> c, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target,
+                    CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(c, arguments, returnStamp, signature, target, callType, invokeKind);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DispatchBeginNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DispatchBeginNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 /**
@@ -31,11 +32,14 @@
 @NodeInfo
 public class DispatchBeginNode extends BeginStateSplitNode {
 
+    public static final NodeClass<DispatchBeginNode> TYPE = NodeClass.create(DispatchBeginNode.class);
+
     public DispatchBeginNode() {
+        super(TYPE);
     }
 
-    public DispatchBeginNode(Stamp stamp) {
-        super(stamp);
+    protected DispatchBeginNode(NodeClass<? extends DispatchBeginNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,10 +30,12 @@
 
 @NodeInfo
 public final class DynamicDeoptimizeNode extends AbstractDeoptimizeNode implements LIRLowerable, Lowerable, Canonicalizable {
+    public static final NodeClass<DynamicDeoptimizeNode> TYPE = NodeClass.create(DynamicDeoptimizeNode.class);
     @Input ValueNode actionAndReason;
     @Input ValueNode speculation;
 
     public DynamicDeoptimizeNode(ValueNode actionAndReason, ValueNode speculation) {
+        super(TYPE, null);
         this.actionAndReason = actionAndReason;
         this.speculation = speculation;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,11 +22,15 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Association})
-public class EndNode extends AbstractEndNode {
+public final class EndNode extends AbstractEndNode {
+    public static final NodeClass<EndNode> TYPE = NodeClass.create(EndNode.class);
+
     public EndNode() {
+        super(TYPE);
     }
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -34,8 +34,10 @@
  */
 @NodeInfo(allowedUsageTypes = {InputType.Association})
 public final class EntryMarkerNode extends BeginStateSplitNode implements IterableNodeType, Simplifiable, LIRLowerable {
+    public static final NodeClass<EntryMarkerNode> TYPE = NodeClass.create(EntryMarkerNode.class);
 
     public EntryMarkerNode() {
+        super(TYPE);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,13 +31,14 @@
 
 @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}", allowedUsageTypes = {InputType.Guard})
 public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowerable, IterableNodeType {
+    public static final NodeClass<FixedGuardNode> TYPE = NodeClass.create(FixedGuardNode.class);
 
     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
         this(condition, deoptReason, action, false);
     }
 
     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
-        super(condition, deoptReason, action, negated);
+        super(TYPE, condition, deoptReason, action, negated);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,13 +23,15 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
 public abstract class FixedNode extends ValueNode {
+    public static final NodeClass<FixedNode> TYPE = NodeClass.create(FixedNode.class);
 
-    public FixedNode(Stamp stamp) {
-        super(stamp);
+    protected FixedNode(NodeClass<? extends FixedNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 /**
@@ -31,6 +32,7 @@
  */
 @NodeInfo
 public abstract class FixedWithNextNode extends FixedNode {
+    public static final NodeClass<FixedWithNextNode> TYPE = NodeClass.create(FixedWithNextNode.class);
 
     @Successor protected FixedNode next;
 
@@ -43,8 +45,8 @@
         next = x;
     }
 
-    public FixedWithNextNode(Stamp stamp) {
-        super(stamp);
+    public FixedWithNextNode(NodeClass<? extends FixedWithNextNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingAnchoredNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingAnchoredNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,21 +23,23 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 
 @NodeInfo
 public abstract class FloatingAnchoredNode extends FloatingNode {
+    public static final NodeClass<FloatingAnchoredNode> TYPE = NodeClass.create(FloatingAnchoredNode.class);
 
     @Input(InputType.Anchor) protected AnchoringNode anchor;
 
-    public FloatingAnchoredNode(Stamp stamp) {
-        super(stamp);
+    public FloatingAnchoredNode(NodeClass<? extends FloatingAnchoredNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
-    public FloatingAnchoredNode(Stamp stamp, AnchoringNode anchor) {
-        super(stamp);
+    public FloatingAnchoredNode(NodeClass<? extends FloatingAnchoredNode> c, Stamp stamp, AnchoringNode anchor) {
+        super(c, stamp);
         this.anchor = anchor;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,21 +23,23 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 
 @NodeInfo
 public abstract class FloatingGuardedNode extends FloatingNode implements GuardedNode {
+    public static final NodeClass<FloatingGuardedNode> TYPE = NodeClass.create(FloatingGuardedNode.class);
 
     @OptionalInput(InputType.Guard) protected GuardingNode guard;
 
-    public FloatingGuardedNode(Stamp stamp) {
-        super(stamp);
+    protected FloatingGuardedNode(NodeClass<? extends FloatingGuardedNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
-    public FloatingGuardedNode(Stamp stamp, GuardingNode guard) {
-        super(stamp);
+    protected FloatingGuardedNode(NodeClass<? extends FloatingGuardedNode> c, Stamp stamp, GuardingNode guard) {
+        super(c, stamp);
         this.guard = guard;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Sat Feb 21 19:55:33 2015 +0100
@@ -41,7 +41,8 @@
  * This can be used as debug or deoptimization information.
  */
 @NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}")
-public class FrameState extends VirtualState implements IterableNodeType {
+public final class FrameState extends VirtualState implements IterableNodeType {
+    public static final NodeClass<FrameState> TYPE = NodeClass.create(FrameState.class);
 
     private static final DebugMetric METRIC_FRAMESTATE_COUNT = Debug.metric("FrameStateCount");
 
@@ -76,6 +77,7 @@
 
     public FrameState(FrameState outerFrameState, ResolvedJavaMethod method, int bci, int localsSize, int stackSize, int lockSize, boolean rethrowException, boolean duringCall,
                     List<MonitorIdNode> monitorIds, List<EscapeObjectState> virtualObjectMappings) {
+        super(TYPE);
         assert stackSize >= 0;
         this.outerFrameState = outerFrameState;
         this.method = method;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FullInfopointNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FullInfopointNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -30,11 +31,12 @@
  * Nodes of this type are inserted into the graph to denote points of interest to debugging.
  */
 @NodeInfo
-public class FullInfopointNode extends InfopointNode implements LIRLowerable, NodeWithState {
+public final class FullInfopointNode extends InfopointNode implements LIRLowerable, NodeWithState {
+    public static final NodeClass<FullInfopointNode> TYPE = NodeClass.create(FullInfopointNode.class);
     @Input(InputType.State) FrameState state;
 
     public FullInfopointNode(InfopointReason reason, FrameState state) {
-        super(reason);
+        super(TYPE, reason);
         this.state = state;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -44,6 +44,7 @@
 @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}", allowedUsageTypes = {InputType.Guard})
 public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, GuardingNode {
 
+    public static final NodeClass<GuardNode> TYPE = NodeClass.create(GuardNode.class);
     @Input(InputType.Condition) protected LogicNode condition;
     protected final DeoptimizationReason reason;
     protected JavaConstant speculation;
@@ -51,7 +52,11 @@
     protected boolean negated;
 
     public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) {
-        super(StampFactory.forVoid(), anchor);
+        this(TYPE, condition, anchor, reason, action, negated, speculation);
+    }
+
+    protected GuardNode(NodeClass<? extends GuardNode> c, LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) {
+        super(c, StampFactory.forVoid(), anchor);
         this.condition = condition;
         this.reason = reason;
         this.action = action;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,17 +31,18 @@
  * Guard {@link PhiNode}s merge guard dependencies at control flow merges.
  */
 @NodeInfo(nameTemplate = "GuardPhi({i#values})", allowedUsageTypes = {InputType.Guard})
-public class GuardPhiNode extends PhiNode implements GuardingNode {
+public final class GuardPhiNode extends PhiNode implements GuardingNode {
 
+    public static final NodeClass<GuardPhiNode> TYPE = NodeClass.create(GuardPhiNode.class);
     @OptionalInput(InputType.Guard) NodeInputList<ValueNode> values;
 
     public GuardPhiNode(AbstractMergeNode merge) {
-        super(StampFactory.forVoid(), merge);
+        super(TYPE, StampFactory.forVoid(), merge);
         this.values = new NodeInputList<>(this);
     }
 
     public GuardPhiNode(AbstractMergeNode merge, ValueNode[] values) {
-        super(StampFactory.forVoid(), merge);
+        super(TYPE, StampFactory.forVoid(), merge);
         this.values = new NodeInputList<>(this, values);
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,12 +29,13 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Guard})
-public class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable {
+public final class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable {
 
+    public static final NodeClass<GuardProxyNode> TYPE = NodeClass.create(GuardProxyNode.class);
     @Input(InputType.Guard) GuardingNode value;
 
     public GuardProxyNode(GuardingNode value, AbstractBeginNode proxyPoint) {
-        super(StampFactory.forVoid(), proxyPoint);
+        super(TYPE, StampFactory.forVoid(), proxyPoint);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,13 +37,14 @@
  * A GuardedValueNode will only go away if its guard is null or {@link StructuredGraph#start()}.
  */
 @NodeInfo
-public class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
+public final class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
 
+    public static final NodeClass<GuardedValueNode> TYPE = NodeClass.create(GuardedValueNode.class);
     @Input ValueNode object;
     protected final Stamp piStamp;
 
     public GuardedValueNode(ValueNode object, GuardingNode guard, Stamp stamp) {
-        super(stamp, guard);
+        super(TYPE, stamp, guard);
         this.object = object;
         this.piStamp = stamp;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -42,6 +42,7 @@
 @NodeInfo(nameTemplate = "GuardingPi(!={p#negated}) {p#reason/s}")
 public final class GuardingPiNode extends FixedWithNextNode implements Lowerable, Virtualizable, Canonicalizable, ValueProxy {
 
+    public static final NodeClass<GuardingPiNode> TYPE = NodeClass.create(GuardingPiNode.class);
     @Input ValueNode object;
     @Input(InputType.Condition) LogicNode condition;
     protected final DeoptimizationReason reason;
@@ -89,7 +90,7 @@
     }
 
     public GuardingPiNode(ValueNode object, ValueNode condition, boolean negateCondition, DeoptimizationReason reason, DeoptimizationAction action, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         assert stamp != null;
         this.piStamp = stamp;
         this.object = object;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -47,7 +47,8 @@
  * of a comparison.
  */
 @NodeInfo
-public class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
+    public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
 
     private static final DebugMetric CORRECTED_PROBABILITIES = Debug.metric("CorrectedProbabilities");
 
@@ -70,7 +71,7 @@
     }
 
     public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.condition = condition;
         this.falseSuccessor = falseSuccessor;
         this.trueSuccessor = trueSuccessor;
@@ -189,6 +190,10 @@
             return;
         }
 
+        if (splitIfAtPhi(tool)) {
+            return;
+        }
+
         if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
             AbstractBeginNode intermediateBegin = falseSuccessor();
             IfNode nextIf = (IfNode) intermediateBegin.next();
@@ -230,7 +235,7 @@
             if (trueSucc instanceof BeginNode && falseSucc instanceof BeginNode && trueSucc.next() instanceof FixedWithNextNode && falseSucc.next() instanceof FixedWithNextNode) {
                 FixedWithNextNode trueNext = (FixedWithNextNode) trueSucc.next();
                 FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next();
-                NodeClass nodeClass = trueNext.getNodeClass();
+                NodeClass<?> nodeClass = trueNext.getNodeClass();
                 if (trueNext.getClass() == falseNext.getClass()) {
                     if (nodeClass.getEdges(Inputs).areEqualIn(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
                         falseNext.replaceAtUsages(trueNext);
@@ -239,7 +244,7 @@
                         graph().addBeforeFixed(this, trueNext);
                         for (Node usage : trueNext.usages().snapshot()) {
                             if (usage.isAlive()) {
-                                NodeClass usageNodeClass = usage.getNodeClass();
+                                NodeClass<?> usageNodeClass = usage.getNodeClass();
                                 if (usageNodeClass.valueNumberable() && !usageNodeClass.isLeafNode()) {
                                     Node newNode = graph().findDuplicate(usage);
                                     if (newNode != null) {
@@ -361,6 +366,16 @@
         return false;
     }
 
+    private static final class MutableProfiledType {
+        final ResolvedJavaType type;
+        double probability;
+
+        public MutableProfiledType(ResolvedJavaType type, double probability) {
+            this.type = type;
+            this.probability = probability;
+        }
+    }
+
     private static boolean prepareForSwap(ConstantReflectionProvider constantReflection, LogicNode a, LogicNode b, double probabilityA, double probabilityB) {
         if (a instanceof InstanceOfNode) {
             InstanceOfNode instanceOfA = (InstanceOfNode) a;
@@ -378,44 +393,8 @@
                 if (instanceOfA.getValue() == instanceOfB.getValue() && !instanceOfA.type().isInterface() && !instanceOfB.type().isInterface() &&
                                 !instanceOfA.type().isAssignableFrom(instanceOfB.type()) && !instanceOfB.type().isAssignableFrom(instanceOfA.type())) {
                     // Two instanceof on the same value with mutually exclusive types.
-                    JavaTypeProfile profileA = instanceOfA.profile();
-                    JavaTypeProfile profileB = instanceOfB.profile();
-
                     Debug.log("Can swap instanceof for types %s and %s", instanceOfA.type(), instanceOfB.type());
-                    JavaTypeProfile newProfile = null;
-                    if (profileA != null && profileB != null) {
-                        double remainder = 1.0;
-                        ArrayList<ProfiledType> profiledTypes = new ArrayList<>();
-                        for (ProfiledType type : profileB.getTypes()) {
-                            if (instanceOfB.type().isAssignableFrom(type.getType())) {
-                                // Do not add to profile.
-                            } else {
-                                ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() * (1.0 - probabilityA) / (1.0 - probabilityB)));
-                                profiledTypes.add(newType);
-                                remainder -= newType.getProbability();
-                            }
-                        }
-
-                        for (ProfiledType type : profileA.getTypes()) {
-                            if (instanceOfA.type().isAssignableFrom(type.getType())) {
-                                ProfiledType newType = new ProfiledType(type.getType(), Math.min(1.0, type.getProbability() / (1.0 - probabilityB)));
-                                profiledTypes.add(newType);
-                                remainder -= newType.getProbability();
-                            }
-                        }
-                        Collections.sort(profiledTypes);
-
-                        if (remainder < 0.0) {
-                            // Can happen due to round-off errors.
-                            remainder = 0.0;
-                        }
-                        newProfile = new JavaTypeProfile(profileB.getNullSeen(), remainder, profiledTypes.toArray(new ProfiledType[profiledTypes.size()]));
-                        Debug.log("First profile: %s", profileA);
-                        Debug.log("Original second profile: %s", profileB);
-                        Debug.log("New second profile: %s", newProfile);
-                    }
-                    instanceOfB.setProfile(profileA);
-                    instanceOfA.setProfile(newProfile);
+                    swapInstanceOfProfiles(probabilityA, probabilityB, instanceOfA, instanceOfB);
                     return true;
                 }
             }
@@ -472,6 +451,116 @@
         return false;
     }
 
+    /**
+     * Arbitrary fraction of not recorded types that we'll guess are sub-types of B.
+     *
+     * This is is used because we can not check if the unrecorded types are sub-types of B or not.
+     */
+    private static final double NOT_RECORDED_SUBTYPE_B = 0.5;
+
+    /**
+     * If the not-recorded fraction of types for the new profile of <code>instanceOfA</code> is
+     * above this threshold, no profile is used for this <code>instanceof</code> after the swap.
+     *
+     * The idea is that the reconstructed profile would contain too much unknowns to be of any use.
+     */
+    private static final double NOT_RECORDED_CUTOFF = 0.4;
+
+    /**
+     * Tries to reconstruct profiles for the swapped <code>instanceof</code> checks.
+     *
+     * The tested types must be mutually exclusive.
+     */
+    private static void swapInstanceOfProfiles(double probabilityA, double probabilityB, InstanceOfNode instanceOfA, InstanceOfNode instanceOfB) {
+        JavaTypeProfile profileA = instanceOfA.profile();
+        JavaTypeProfile profileB = instanceOfB.profile();
+
+        JavaTypeProfile newProfileA = null;
+        JavaTypeProfile newProfileB = null;
+        if (profileA != null || profileB != null) {
+            List<MutableProfiledType> newProfiledTypesA = new ArrayList<>();
+            List<MutableProfiledType> newProfiledTypesB = new ArrayList<>();
+            double totalProbabilityA = 0.0;
+            double totalProbabilityB = 0.0;
+            double newNotRecordedA = 0.0;
+            double newNotRecordedB = 0.0;
+            TriState nullSeen = TriState.UNKNOWN;
+            if (profileA != null) {
+                for (ProfiledType profiledType : profileA.getTypes()) {
+                    newProfiledTypesB.add(new MutableProfiledType(profiledType.getType(), profiledType.getProbability()));
+                    totalProbabilityB += profiledType.getProbability();
+                    if (!instanceOfB.type().isAssignableFrom(profiledType.getType())) {
+                        double typeProbabilityA = profiledType.getProbability() / (1 - probabilityB);
+                        newProfiledTypesA.add(new MutableProfiledType(profiledType.getType(), typeProbabilityA));
+                        totalProbabilityA += typeProbabilityA;
+                    }
+                }
+                newNotRecordedB += profileA.getNotRecordedProbability();
+                newNotRecordedA += NOT_RECORDED_SUBTYPE_B * profileA.getNotRecordedProbability() / (1 - probabilityB);
+                nullSeen = profileA.getNullSeen();
+            }
+            int searchA = newProfiledTypesA.size();
+            int searchB = newProfiledTypesB.size();
+            if (profileB != null) {
+                for (ProfiledType profiledType : profileB.getTypes()) {
+                    double typeProbabilityB = profiledType.getProbability() * (1 - probabilityA);
+                    appendOrMerge(profiledType.getType(), typeProbabilityB, searchB, newProfiledTypesB);
+                    totalProbabilityB += typeProbabilityB;
+                    if (!instanceOfB.type().isAssignableFrom(profiledType.getType())) {
+                        double typeProbabilityA = typeProbabilityB / (1 - probabilityB);
+                        appendOrMerge(profiledType.getType(), typeProbabilityA, searchA, newProfiledTypesA);
+                        totalProbabilityA += typeProbabilityA;
+                    }
+                }
+                newNotRecordedB += profileB.getNotRecordedProbability() * (1 - probabilityA);
+                newNotRecordedA += NOT_RECORDED_SUBTYPE_B * profileB.getNotRecordedProbability() * (1 - probabilityA) / (1 - probabilityB);
+                nullSeen = TriState.merge(nullSeen, profileB.getNullSeen());
+            }
+            totalProbabilityA += newNotRecordedA;
+            totalProbabilityB += newNotRecordedB;
+
+            if (newNotRecordedA / NOT_RECORDED_SUBTYPE_B > NOT_RECORDED_CUTOFF) {
+                // too much unknown
+                newProfileA = null;
+            } else {
+                newProfileA = makeProfile(totalProbabilityA, newNotRecordedA, newProfiledTypesA, nullSeen);
+            }
+            newProfileB = makeProfile(totalProbabilityB, newNotRecordedB, newProfiledTypesB, nullSeen);
+        }
+
+        instanceOfB.setProfile(newProfileB);
+        instanceOfA.setProfile(newProfileA);
+    }
+
+    private static JavaTypeProfile makeProfile(double totalProbability, double notRecorded, List<MutableProfiledType> profiledTypes, TriState nullSeen) {
+        // protect against NaNs and empty profiles
+        if (totalProbability > 0.0) {
+            // normalize
+            ProfiledType[] profiledTypesArray = new ProfiledType[profiledTypes.size()];
+            int i = 0;
+            for (MutableProfiledType profiledType : profiledTypes) {
+                profiledTypesArray[i++] = new ProfiledType(profiledType.type, profiledType.probability / totalProbability);
+            }
+
+            // sort
+            Arrays.sort(profiledTypesArray);
+
+            return new JavaTypeProfile(nullSeen, notRecorded / totalProbability, profiledTypesArray);
+        }
+        return null;
+    }
+
+    private static void appendOrMerge(ResolvedJavaType type, double probability, int searchUntil, List<MutableProfiledType> list) {
+        for (int i = 0; i < searchUntil; i++) {
+            MutableProfiledType profiledType = list.get(i);
+            if (profiledType.type.equals(type)) {
+                profiledType.probability += probability;
+                return;
+            }
+        }
+        list.add(new MutableProfiledType(type, probability));
+    }
+
     private static boolean valuesDistinct(ConstantReflectionProvider constantReflection, ValueNode a, ValueNode b) {
         if (a.isConstant() && b.isConstant()) {
             Boolean equal = constantReflection.constantEquals(a.asConstant(), b.asConstant());
@@ -512,7 +601,6 @@
                      * Multiple phis but merging same values for true and false, so simply delete
                      * the path
                      */
-                    tool.addToWorkList(condition());
                     removeThroughFalseBranch(tool);
                     return true;
                 } else if (distinct == 1) {
@@ -555,6 +643,9 @@
         AbstractBeginNode trueBegin = trueSuccessor();
         graph().removeSplitPropagate(this, trueBegin, tool);
         tool.addToWorkList(trueBegin);
+        if (condition().isAlive() && condition().hasNoUsages()) {
+            GraphUtil.killWithUnusedFloatingInputs(condition());
+        }
     }
 
     private ConditionalNode canonicalizeConditionalCascade(ValueNode trueValue, ValueNode falseValue) {
@@ -602,6 +693,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 (EndNode 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:
      *
@@ -684,7 +906,7 @@
             }
         }
 
-        List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
         assert phi.valueCount() == merge.forwardEndCount();
 
         Constant[] xs = constantValues(compare.getX(), merge, false);
@@ -698,8 +920,8 @@
             return false;
         }
 
-        List<AbstractEndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
-        List<AbstractEndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
+        List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
+        List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
         Map<AbstractEndNode, ValueNode> phiValues = CollectionsFactory.newMap(mergePredecessors.size());
 
         AbstractBeginNode oldFalseSuccessor = falseSuccessor();
@@ -708,9 +930,9 @@
         setFalseSuccessor(null);
         setTrueSuccessor(null);
 
-        Iterator<AbstractEndNode> ends = mergePredecessors.iterator();
+        Iterator<EndNode> ends = mergePredecessors.iterator();
         for (int i = 0; i < xs.length; i++) {
-            AbstractEndNode end = ends.next();
+            EndNode end = ends.next();
             phiValues.put(end, phi.valueAt(end));
             if (compare.condition().foldCondition(xs[i], ys[i], tool.getConstantReflection(), compare.unorderedIsTrue())) {
                 trueEnds.add(end);
@@ -840,7 +1062,7 @@
      * @param oldMerge the merge being removed
      * @param phiValues the values of the phi at the merge, keyed by the merge ends
      */
-    private void connectEnds(List<AbstractEndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) {
+    private void connectEnds(List<EndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, AbstractMergeNode oldMerge, SimplifierTool tool) {
         if (!ends.isEmpty()) {
             if (ends.size() == 1) {
                 AbstractEndNode end = ends.get(0);
@@ -854,7 +1076,7 @@
                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
                 PhiNode newPhi = graph().addWithoutUnique(new ValuePhiNode(oldPhi.stamp(), newMerge));
 
-                for (AbstractEndNode end : ends) {
+                for (EndNode end : ends) {
                     newPhi.addInput(phiValues.get(end));
                     newMerge.addForwardEnd(end);
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Sat Feb 21 19:55:33 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
@@ -27,16 +27,18 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public class IndirectCallTargetNode extends LoweredCallTargetNode {
+public abstract class IndirectCallTargetNode extends LoweredCallTargetNode {
+    public static final NodeClass<IndirectCallTargetNode> TYPE = NodeClass.create(IndirectCallTargetNode.class);
 
     @Input protected ValueNode computedAddress;
 
-    public IndirectCallTargetNode(ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType,
-                    InvokeKind invokeKind) {
-        super(arguments, returnStamp, signature, target, callType, invokeKind);
+    protected IndirectCallTargetNode(NodeClass<? extends IndirectCallTargetNode> c, ValueNode computedAddress, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature,
+                    ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(c, arguments, returnStamp, signature, target, callType, invokeKind);
         this.computedAddress = computedAddress;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -24,14 +24,16 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
 public abstract class InfopointNode extends FixedWithNextNode {
+    public static final NodeClass<InfopointNode> TYPE = NodeClass.create(InfopointNode.class);
     protected final InfopointReason reason;
 
-    public InfopointNode(InfopointReason reason) {
-        super(StampFactory.forVoid());
+    public InfopointNode(NodeClass<? extends InfopointNode> c, InfopointReason reason) {
+        super(c, StampFactory.forVoid());
         this.reason = reason;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -37,7 +37,8 @@
  * The {@code InvokeNode} represents all kinds of method calls.
  */
 @NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}", allowedUsageTypes = {InputType.Memory})
-public class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
+public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
+    public static final NodeClass<InvokeNode> TYPE = NodeClass.create(InvokeNode.class);
 
     @Input(InputType.Extension) CallTargetNode callTarget;
     @OptionalInput(InputType.State) FrameState stateDuring;
@@ -51,7 +52,7 @@
     }
 
     public InvokeNode(CallTargetNode callTarget, int bci, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         this.callTarget = callTarget;
         this.bci = bci;
         this.polymorphic = false;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -33,7 +33,8 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}", allowedUsageTypes = {InputType.Memory})
-public class InvokeWithExceptionNode extends ControlSplitNode implements Invoke, MemoryCheckpoint.Single, LIRLowerable {
+public final class InvokeWithExceptionNode extends ControlSplitNode implements Invoke, MemoryCheckpoint.Single, LIRLowerable {
+    public static final NodeClass<InvokeWithExceptionNode> TYPE = NodeClass.create(InvokeWithExceptionNode.class);
 
     private static final double EXCEPTION_PROBA = 1e-5;
 
@@ -49,7 +50,7 @@
     protected double exceptionProbability;
 
     public InvokeWithExceptionNode(CallTargetNode callTarget, AbstractBeginNode exceptionEdge, int bci) {
-        super(callTarget.returnStamp());
+        super(TYPE, callTarget.returnStamp());
         this.exceptionEdge = exceptionEdge;
         this.bci = bci;
         this.callTarget = callTarget;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Sat Feb 21 19:55:33 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
@@ -23,15 +23,18 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single {
+public final class KillingBeginNode extends AbstractBeginNode implements MemoryCheckpoint.Single {
 
+    public static final NodeClass<KillingBeginNode> TYPE = NodeClass.create(KillingBeginNode.class);
     protected LocationIdentity locationIdentity;
 
     public KillingBeginNode(LocationIdentity locationIdentity) {
+        super(TYPE);
         this.locationIdentity = locationIdentity;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -30,12 +30,13 @@
  * The {@code LogicConstantNode} represents a boolean constant.
  */
 @NodeInfo(nameTemplate = "{p#value}")
-public class LogicConstantNode extends LogicNode implements LIRLowerable {
+public final class LogicConstantNode extends LogicNode implements LIRLowerable {
 
+    public static final NodeClass<LogicConstantNode> TYPE = NodeClass.create(LogicConstantNode.class);
     protected final boolean value;
 
     public LogicConstantNode(boolean value) {
-        super();
+        super(TYPE);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 
@@ -29,25 +30,45 @@
  * Logic node that negates its argument.
  */
 @NodeInfo
-public class LogicNegationNode extends LogicNode implements Canonicalizable.Unary<LogicNode> {
+public final class LogicNegationNode extends LogicNode implements Canonicalizable.Unary<LogicNode> {
 
+    public static final NodeClass<LogicNegationNode> TYPE = NodeClass.create(LogicNegationNode.class);
     @Input(InputType.Condition) LogicNode value;
 
     public LogicNegationNode(LogicNode value) {
+        super(TYPE);
         this.value = value;
     }
 
+    public static LogicNode create(LogicNode value) {
+        LogicNode synonym = findSynonym(value);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new LogicNegationNode(value);
+    }
+
+    private static LogicNode findSynonym(LogicNode value) {
+        if (value instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) value;
+            return LogicConstantNode.forBoolean(!logicConstantNode.getValue());
+        } else if (value instanceof LogicNegationNode) {
+            return ((LogicNegationNode) value).getValue();
+        }
+        return null;
+    }
+
     public LogicNode getValue() {
         return value;
     }
 
     @Override
     public LogicNode canonical(CanonicalizerTool tool, LogicNode forValue) {
-        if (forValue instanceof LogicNegationNode) {
-            return ((LogicNegationNode) forValue).getValue();
-        } else {
-            return this;
+        LogicNode synonym = findSynonym(forValue);
+        if (synonym != null) {
+            return synonym;
         }
+        return this;
     }
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,14 +25,17 @@
 import static com.oracle.graal.nodeinfo.InputType.*;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.calc.*;
 
 @NodeInfo(allowedUsageTypes = {Condition})
 public abstract class LogicNode extends FloatingNode {
 
-    public LogicNode() {
-        super(StampFactory.forVoid());
+    public static final NodeClass<LogicNode> TYPE = NodeClass.create(LogicNode.class);
+
+    public LogicNode(NodeClass<? extends LogicNode> c) {
+        super(c, StampFactory.forVoid());
     }
 
     public static LogicNode and(LogicNode a, LogicNode b, double shortCircuitProbability) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -37,14 +37,18 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo
-public class LoopBeginNode extends AbstractMergeNode implements IterableNodeType, LIRLowerable {
+public final class LoopBeginNode extends AbstractMergeNode implements IterableNodeType, LIRLowerable {
 
+    public static final NodeClass<LoopBeginNode> TYPE = NodeClass.create(LoopBeginNode.class);
     protected double loopFrequency;
     protected int nextEndIndex;
     protected int unswitches;
+    protected int inversionCount;
+
     @OptionalInput(InputType.Guard) GuardingNode overflowGuard;
 
     public LoopBeginNode() {
+        super(TYPE);
         loopFrequency = 1;
     }
 
@@ -94,16 +98,12 @@
      *
      * @return the set of {@code LoopEndNode} that correspond to back-edges for this loop
      */
-    public List<LoopEndNode> orderedLoopEnds() {
-        List<LoopEndNode> snapshot = loopEnds().snapshot();
-        Collections.sort(snapshot, new Comparator<LoopEndNode>() {
-
-            @Override
-            public int compare(LoopEndNode o1, LoopEndNode o2) {
-                return o1.endIndex() - o2.endIndex();
-            }
-        });
-        return snapshot;
+    public LoopEndNode[] orderedLoopEnds() {
+        LoopEndNode[] result = new LoopEndNode[this.getLoopEndCount()];
+        for (LoopEndNode end : loopEnds()) {
+            result[end.endIndex()] = end;
+        }
+        return result;
     }
 
     public AbstractEndNode forwardEnd() {
@@ -149,7 +149,7 @@
                 return loopEnd.endIndex() + forwardEndCount();
             }
         } else {
-            return super.forwardEndIndex(pred);
+            return super.forwardEndIndex((EndNode) pred);
         }
         throw ValueNodeUtil.shouldNotReachHere("unknown pred : " + pred);
     }
@@ -179,14 +179,26 @@
         return nextEndIndex++;
     }
 
+    public int getLoopEndCount() {
+        return nextEndIndex;
+    }
+
     public int unswitches() {
         return unswitches;
     }
 
-    public void incUnswitches() {
+    public void incrementUnswitches() {
         unswitches++;
     }
 
+    public int getInversionCount() {
+        return inversionCount;
+    }
+
+    public void setInversionCount(int count) {
+        inversionCount = count;
+    }
+
     @Override
     public void simplify(SimplifierTool tool) {
         removeDeadPhis();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -33,13 +33,15 @@
  * {@linkplain #loopBegin() loop header}.
  */
 @NodeInfo
-public class LoopEndNode extends AbstractEndNode {
+public final class LoopEndNode extends AbstractEndNode {
 
+    public static final NodeClass<LoopEndNode> TYPE = NodeClass.create(LoopEndNode.class);
     @Input(InputType.Association) LoopBeginNode loopBegin;
     protected boolean canSafepoint;
     protected int endIndex;
 
     public LoopEndNode(LoopBeginNode begin) {
+        super(TYPE);
         int idx = begin.nextEndIndex();
         assert idx >= 0;
         this.endIndex = idx;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -27,11 +27,13 @@
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Association})
-public class LoopExitNode extends BeginStateSplitNode implements IterableNodeType {
+public final class LoopExitNode extends BeginStateSplitNode implements IterableNodeType {
 
+    public static final NodeClass<LoopExitNode> TYPE = NodeClass.create(LoopExitNode.class);
     @Input(InputType.Association) LoopBeginNode loopBegin;
 
     public LoopExitNode(LoopBeginNode loop) {
+        super(TYPE);
         assert loop != null;
         loopBegin = loop;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Sat Feb 21 19:55:33 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
@@ -27,17 +27,20 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
 public abstract class LoweredCallTargetNode extends CallTargetNode {
 
+    public static final NodeClass<LoweredCallTargetNode> TYPE = NodeClass.create(LoweredCallTargetNode.class);
     protected final Stamp returnStamp;
     protected final JavaType[] signature;
     protected final CallingConvention.Type callType;
 
-    public LoweredCallTargetNode(List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target, CallingConvention.Type callType, InvokeKind invokeKind) {
-        super(arguments, target, invokeKind);
+    protected LoweredCallTargetNode(NodeClass<? extends LoweredCallTargetNode> c, List<ValueNode> arguments, Stamp returnStamp, JavaType[] signature, ResolvedJavaMethod target,
+                    CallingConvention.Type callType, InvokeKind invokeKind) {
+        super(c, arguments, target, invokeKind);
         this.returnStamp = returnStamp;
         this.signature = signature;
         this.callType = callType;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Sat Feb 21 19:55:33 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
@@ -38,6 +38,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Extension})
 public final class MemoryMapNode extends FloatingNode implements MemoryMap, LIRLowerable {
 
+    public static final NodeClass<MemoryMapNode> TYPE = NodeClass.create(MemoryMapNode.class);
     protected final List<LocationIdentity> locationIdentities;
     @Input(InputType.Memory) NodeInputList<ValueNode> nodes;
 
@@ -51,7 +52,7 @@
     }
 
     public MemoryMapNode(Map<LocationIdentity, MemoryNode> mmap) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         locationIdentities = new ArrayList<>(mmap.keySet());
         nodes = new NodeInputList<>(this, mmap.values());
         assert checkOrder(mmap);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -34,17 +34,18 @@
 @NodeInfo(nameTemplate = "MemoryPhi({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory})
 public final class MemoryPhiNode extends PhiNode implements MemoryNode {
 
+    public static final NodeClass<MemoryPhiNode> TYPE = NodeClass.create(MemoryPhiNode.class);
     @Input(InputType.Memory) NodeInputList<ValueNode> values;
     protected final LocationIdentity locationIdentity;
 
     public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity) {
-        super(StampFactory.forVoid(), merge);
+        super(TYPE, StampFactory.forVoid(), merge);
         this.locationIdentity = locationIdentity;
         this.values = new NodeInputList<>(this);
     }
 
     public MemoryPhiNode(AbstractMergeNode merge, LocationIdentity locationIdentity, ValueNode[] values) {
-        super(StampFactory.forVoid(), merge);
+        super(TYPE, StampFactory.forVoid(), merge);
         this.locationIdentity = locationIdentity;
         this.values = new NodeInputList<>(this, values);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
 /**
@@ -29,6 +30,10 @@
  */
 @NodeInfo
 public final class MergeNode extends AbstractMergeNode {
+
+    public static final NodeClass<MergeNode> TYPE = NodeClass.create(MergeNode.class);
+
     public MergeNode() {
+        super(TYPE);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -32,10 +32,12 @@
  * The {@code Parameter} instruction is a placeholder for an incoming argument to a function call.
  */
 @NodeInfo(nameTemplate = "Param({p#index})")
-public class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider {
+public final class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider {
+
+    public static final NodeClass<ParameterNode> TYPE = NodeClass.create(ParameterNode.class);
 
     public ParameterNode(int index, Stamp stamp) {
-        super(index, stamp);
+        super(TYPE, index, stamp);
     }
 
     public Stamp uncheckedStamp() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,10 +41,11 @@
 @NodeInfo
 public abstract class PhiNode extends FloatingNode implements Simplifiable {
 
+    public static final NodeClass<PhiNode> TYPE = NodeClass.create(PhiNode.class);
     @Input(InputType.Association) protected AbstractMergeNode merge;
 
-    protected PhiNode(Stamp stamp, AbstractMergeNode merge) {
-        super(stamp);
+    protected PhiNode(NodeClass<? extends PhiNode> c, Stamp stamp, AbstractMergeNode merge) {
+        super(c, stamp);
         this.merge = merge;
     }
 
@@ -142,10 +143,12 @@
     }
 
     @NodeInfo
-    static class MultipleValuesNode extends ValueNode {
+    static final class MultipleValuesNode extends ValueNode {
+
+        public static final NodeClass<MultipleValuesNode> TYPE = NodeClass.create(MultipleValuesNode.class);
 
         public MultipleValuesNode() {
-            super(null);
+            super(TYPE, null);
         }
 
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,8 +36,9 @@
  * this information.
  */
 @NodeInfo
-public class PiArrayNode extends PiNode implements ArrayLengthProvider {
+public final class PiArrayNode extends PiNode implements ArrayLengthProvider {
 
+    public static final NodeClass<PiArrayNode> TYPE = NodeClass.create(PiArrayNode.class);
     @Input ValueNode length;
 
     public ValueNode length() {
@@ -45,7 +46,7 @@
     }
 
     public PiArrayNode(ValueNode object, ValueNode length, Stamp stamp) {
-        super(object, stamp);
+        super(TYPE, object, stamp);
         this.length = length;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -44,6 +44,7 @@
 @NodeInfo
 public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
 
+    public static final NodeClass<PiNode> TYPE = NodeClass.create(PiNode.class);
     @Input ValueNode object;
     protected final Stamp piStamp;
 
@@ -51,14 +52,18 @@
         return object;
     }
 
+    protected PiNode(NodeClass<? extends PiNode> c, ValueNode object, Stamp stamp) {
+        super(c, stamp, null);
+        this.object = object;
+        this.piStamp = stamp;
+    }
+
     public PiNode(ValueNode object, Stamp stamp) {
-        super(stamp);
-        this.piStamp = stamp;
-        this.object = object;
+        this(object, stamp, null);
     }
 
     public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
-        super(stamp, (GuardingNode) anchor);
+        super(TYPE, stamp, (GuardingNode) anchor);
         this.object = object;
         this.piStamp = stamp;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,10 +36,11 @@
 @NodeInfo
 public abstract class ProxyNode extends FloatingNode implements IterableNodeType, ValueNumberable {
 
+    public static final NodeClass<ProxyNode> TYPE = NodeClass.create(ProxyNode.class);
     @Input(InputType.Association) AbstractBeginNode proxyPoint;
 
-    public ProxyNode(Stamp stamp, AbstractBeginNode proxyPoint) {
-        super(stamp);
+    protected ProxyNode(NodeClass<? extends ProxyNode> c, Stamp stamp, AbstractBeginNode proxyPoint) {
+        super(c, stamp);
         assert proxyPoint != null;
         this.proxyPoint = proxyPoint;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -28,8 +28,9 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class ReturnNode extends ControlSinkNode implements LIRLowerable, IterableNodeType {
+public final class ReturnNode extends ControlSinkNode implements LIRLowerable, IterableNodeType {
 
+    public static final NodeClass<ReturnNode> TYPE = NodeClass.create(ReturnNode.class);
     @OptionalInput ValueNode result;
     @OptionalInput(InputType.Extension) MemoryMapNode memoryMap;
 
@@ -42,7 +43,7 @@
     }
 
     public ReturnNode(ValueNode result, MemoryMapNode memoryMap) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.result = result;
         this.memoryMap = memoryMap;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -30,10 +31,12 @@
  * Marks a position in the graph where a safepoint should be emitted.
  */
 @NodeInfo
-public class SafepointNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
+public final class SafepointNode extends DeoptimizingFixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<SafepointNode> TYPE = NodeClass.create(SafepointNode.class);
 
     public SafepointNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,8 +27,9 @@
 import com.oracle.graal.nodeinfo.*;
 
 @NodeInfo
-public class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable.Binary<LogicNode> {
+public final class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable.Binary<LogicNode> {
 
+    public static final NodeClass<ShortCircuitOrNode> TYPE = NodeClass.create(ShortCircuitOrNode.class);
     @Input(InputType.Condition) LogicNode x;
     @Input(InputType.Condition) LogicNode y;
     protected boolean xNegated;
@@ -36,6 +37,7 @@
     protected double shortCircuitProbability;
 
     public ShortCircuitOrNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) {
+        super(TYPE);
         this.x = x;
         this.xNegated = xNegated;
         this.y = y;
@@ -105,7 +107,7 @@
             if (isXNegated()) {
                 if (isYNegated()) {
                     // !a || !a = !a
-                    return new LogicNegationNode(forX);
+                    return LogicNegationNode.create(forX);
                 } else {
                     // !a || a = true
                     return LogicConstantNode.tautology();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -29,11 +29,12 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class SimpleInfopointNode extends InfopointNode implements LIRLowerable, IterableNodeType, Simplifiable {
+public final class SimpleInfopointNode extends InfopointNode implements LIRLowerable, IterableNodeType, Simplifiable {
+    public static final NodeClass<SimpleInfopointNode> TYPE = NodeClass.create(SimpleInfopointNode.class);
     protected BytecodePosition position;
 
     public SimpleInfopointNode(InfopointReason reason, BytecodePosition position) {
-        super(reason);
+        super(TYPE, reason);
         this.position = position;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 
@@ -31,7 +32,14 @@
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint.Single {
+    public static final NodeClass<StartNode> TYPE = NodeClass.create(StartNode.class);
+
+    protected StartNode(NodeClass<? extends StartNode> c) {
+        super(c);
+    }
+
     public StartNode() {
+        super(TYPE);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Sat Feb 21 19:55:33 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,40 +107,51 @@
     private boolean hasValueProxies = true;
 
     /**
+     * The assumptions made while constructing and transforming this graph.
+     */
+    private final Assumptions assumptions;
+
+    /**
+     * The methods that were inlined while constructing this graph.
+     */
+    private Set<ResolvedJavaMethod> inlinedMethods = 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() {
         Stamp returnStamp = null;
-        for (ReturnNode returnNode : getNodes(ReturnNode.class)) {
+        for (ReturnNode returnNode : getNodes(ReturnNode.TYPE)) {
             ValueNode result = returnNode.result();
             if (result != null) {
                 if (returnStamp == null) {
@@ -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), isInlinedMethodRecordingEnabled());
+    }
+
+    public StructuredGraph copy(String newName, ResolvedJavaMethod newMethod, AllowAssumptions allowAssumptions, boolean enableInlinedMethodRecording) {
+        StructuredGraph copy = new StructuredGraph(newName, newMethod, graphId, entryBCI, allowAssumptions);
+        if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
+            copy.assumptions.record(assumptions);
+        }
+        if (!enableInlinedMethodRecording) {
+            copy.disableInlinedMethodRecording();
+        }
         copy.setGuardsStage(getGuardsStage());
         copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase;
         copy.hasValueProxies = hasValueProxies;
@@ -212,7 +246,7 @@
     }
 
     public ParameterNode getParameter(int index) {
-        for (ParameterNode param : getNodes(ParameterNode.class)) {
+        for (ParameterNode param : getNodes(ParameterNode.TYPE)) {
             if (param.index() == index) {
                 return param;
             }
@@ -221,7 +255,7 @@
     }
 
     public Iterable<Invoke> getInvokes() {
-        final Iterator<MethodCallTargetNode> callTargets = getNodes(MethodCallTargetNode.class).iterator();
+        final Iterator<MethodCallTargetNode> callTargets = getNodes(MethodCallTargetNode.TYPE).iterator();
         return new Iterable<Invoke>() {
 
             private Invoke next;
@@ -265,7 +299,7 @@
     }
 
     public boolean hasLoops() {
-        return hasNode(LoopBeginNode.class);
+        return hasNode(LoopBeginNode.TYPE);
     }
 
     public void removeFloating(FloatingNode node) {
@@ -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 methods inlined while constructing this graph. This can be done at most
+     * once and must be done before any inlined methods are recorded.
+     */
+    public void disableInlinedMethodRecording() {
+        assert inlinedMethods != null : "cannot disable inlined method recording more than once";
+        assert inlinedMethods.isEmpty() : "cannot disable inlined method recording once methods have been recorded";
+        inlinedMethods = null;
+    }
+
+    public boolean isInlinedMethodRecordingEnabled() {
+        return inlinedMethods != null;
+    }
+
+    /**
+     * Gets the methods that were inlined while constructing this graph.
+     *
+     * @return {@code null} if inlined method recording has been
+     *         {@linkplain #disableInlinedMethodRecording() disabled}
+     */
+    public Set<ResolvedJavaMethod> getInlinedMethods() {
+        return inlinedMethods;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,8 +37,9 @@
  * A node that attaches a type profile to a proxied input node.
  */
 @NodeInfo
-public class TypeProfileProxyNode extends UnaryNode implements IterableNodeType, ValueProxy {
+public final class TypeProfileProxyNode extends UnaryNode implements IterableNodeType, ValueProxy {
 
+    public static final NodeClass<TypeProfileProxyNode> TYPE = NodeClass.create(TypeProfileProxyNode.class);
     protected final JavaTypeProfile profile;
     protected transient ResolvedJavaType lastCheckedType;
     protected transient JavaTypeProfile lastCheckedProfile;
@@ -59,7 +60,7 @@
     }
 
     protected TypeProfileProxyNode(ValueNode value, JavaTypeProfile profile) {
-        super(value.stamp(), value);
+        super(TYPE, value.stamp(), value);
         this.profile = profile;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
@@ -29,13 +30,15 @@
 @NodeInfo
 public abstract class UnaryOpLogicNode extends LogicNode implements LIRLowerable, Canonicalizable.Unary<ValueNode> {
 
+    public static final NodeClass<UnaryOpLogicNode> TYPE = NodeClass.create(UnaryOpLogicNode.class);
     @Input protected ValueNode value;
 
     public ValueNode getValue() {
         return value;
     }
 
-    public UnaryOpLogicNode(ValueNode value) {
+    public UnaryOpLogicNode(NodeClass<? extends UnaryOpLogicNode> c, ValueNode value) {
+        super(c);
         assert value != null;
         this.value = value;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
 
@@ -31,8 +32,9 @@
  * Unwinds the current frame to an exception handler in the caller frame.
  */
 @NodeInfo
-public class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable {
+public final class UnwindNode extends ControlSinkNode implements Lowerable, LIRLowerable {
 
+    public static final NodeClass<UnwindNode> TYPE = NodeClass.create(UnwindNode.class);
     @Input ValueNode exception;
 
     public ValueNode exception() {
@@ -40,7 +42,7 @@
     }
 
     public UnwindNode(ValueNode exception) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         assert exception == null || exception.getKind() == Kind.Object;
         this.exception = exception;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodeinfo.*;
 
@@ -34,13 +35,15 @@
 @NodeInfo
 public abstract class ValueNode extends com.oracle.graal.graph.Node implements KindProvider {
 
+    public static final NodeClass<ValueNode> TYPE = NodeClass.create(ValueNode.class);
     /**
      * The kind of this value. This is {@link Kind#Void} for instructions that produce no value.
      * This kind is guaranteed to be a {@linkplain Kind#getStackKind() stack kind}.
      */
     protected Stamp stamp;
 
-    public ValueNode(Stamp stamp) {
+    public ValueNode(NodeClass<? extends ValueNode> c, Stamp stamp) {
+        super(c);
         this.stamp = stamp;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Sat Feb 21 19:55:33 2015 +0100
@@ -88,7 +88,7 @@
      * Converts a given instruction to a value string. The representation of an node as a value is
      * formed by concatenating the {@linkplain com.oracle.graal.api.meta.Kind#getTypeChar character}
      * denoting its {@linkplain ValueNode#getKind kind} and its id. For example, {@code "i13"}.
-     * 
+     *
      * @param value the instruction to convert to a value string. If {@code value == null}, then "-"
      *            is returned.
      * @return the instruction representation as a string
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -33,16 +33,21 @@
 @NodeInfo(nameTemplate = "ValuePhi({i#values})")
 public class ValuePhiNode extends PhiNode {
 
+    public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
     @Input protected NodeInputList<ValueNode> values;
 
     public ValuePhiNode(Stamp stamp, AbstractMergeNode merge) {
-        super(stamp, merge);
+        this(TYPE, stamp, merge);
+    }
+
+    protected ValuePhiNode(NodeClass<? extends ValuePhiNode> c, Stamp stamp, AbstractMergeNode merge) {
+        super(c, stamp, merge);
         assert stamp != StampFactory.forVoid();
         values = new NodeInputList<>(this);
     }
 
     public ValuePhiNode(Stamp stamp, AbstractMergeNode merge, ValueNode[] values) {
-        super(stamp, merge);
+        super(TYPE, stamp, merge);
         assert stamp != StampFactory.forVoid();
         this.values = new NodeInputList<>(this, values);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 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
@@ -28,12 +28,13 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy {
+public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy {
 
+    public static final NodeClass<ValueProxyNode> TYPE = NodeClass.create(ValueProxyNode.class);
     @Input ValueNode value;
 
     public ValueProxyNode(ValueNode value, AbstractBeginNode proxyPoint) {
-        super(value.stamp(), proxyPoint);
+        super(TYPE, value.stamp(), proxyPoint);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Sat Feb 21 19:55:33 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
@@ -32,6 +32,12 @@
 @NodeInfo(allowedUsageTypes = {InputType.State})
 public abstract class VirtualState extends Node {
 
+    protected VirtualState(NodeClass<? extends VirtualState> c) {
+        super(c);
+    }
+
+    public static final NodeClass<VirtualState> TYPE = NodeClass.create(VirtualState.class);
+
     public abstract static class NodeClosure<T extends Node> {
 
         public abstract void apply(Node usage, T node);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Abs;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,9 +36,10 @@
  */
 @NodeInfo
 public final class AbsNode extends UnaryArithmeticNode<Abs> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+    public static final NodeClass<AbsNode> TYPE = NodeClass.create(AbsNode.class);
 
     public AbsNode(ValueNode x) {
-        super(ArithmeticOpTable::getAbs, x);
+        super(TYPE, ArithmeticOpTable::getAbs, x);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Add;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,8 +36,14 @@
 @NodeInfo(shortName = "+")
 public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode {
 
+    public static final NodeClass<AddNode> TYPE = NodeClass.create(AddNode.class);
+
     public AddNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getAdd, x, y);
+        this(TYPE, x, y);
+    }
+
+    protected AddNode(NodeClass<? extends AddNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getAdd, x, y);
     }
 
     public static ValueNode create(ValueNode x, ValueNode y) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 +25,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.And;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -36,8 +38,21 @@
 @NodeInfo(shortName = "&")
 public final class AndNode extends BinaryArithmeticNode<And> implements NarrowableArithmeticNode {
 
+    public static final NodeClass<AndNode> TYPE = NodeClass.create(AndNode.class);
+
     public AndNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getAnd, x, y);
+        super(TYPE, ArithmeticOpTable::getAnd, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<And> op = ArithmeticOpTable.forStamp(x.stamp()).getAnd();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new AndNode(x, y);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,13 +39,15 @@
 @NodeInfo
 public abstract class BinaryArithmeticNode<OP> extends BinaryNode implements ArithmeticLIRLowerable {
 
+    @SuppressWarnings("rawtypes") public static final NodeClass<BinaryArithmeticNode> TYPE = NodeClass.create(BinaryArithmeticNode.class);
+
     protected interface SerializableBinaryFunction<T> extends Function<ArithmeticOpTable, BinaryOp<T>>, Serializable {
     }
 
     protected final SerializableBinaryFunction<OP> getOp;
 
-    public BinaryArithmeticNode(SerializableBinaryFunction<OP> getOp, ValueNode x, ValueNode y) {
-        super(getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), y.stamp()), x, y);
+    protected BinaryArithmeticNode(NodeClass<? extends BinaryArithmeticNode<OP>> c, SerializableBinaryFunction<OP> getOp, ValueNode x, ValueNode y) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), y.stamp()), x, y);
         this.getOp = getOp;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.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.*;
@@ -33,6 +34,7 @@
 @NodeInfo
 public abstract class BinaryNode extends FloatingNode implements Canonicalizable.Binary<ValueNode> {
 
+    public static final NodeClass<BinaryNode> TYPE = NodeClass.create(BinaryNode.class);
     @Input protected ValueNode x;
     @Input protected ValueNode y;
 
@@ -61,8 +63,8 @@
      * @param x the first input instruction
      * @param y the second input instruction
      */
-    public BinaryNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp);
+    protected BinaryNode(NodeClass<? extends BinaryNode> c, Stamp stamp, ValueNode x, ValueNode y) {
+        super(c, stamp);
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 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.*;
@@ -39,6 +40,7 @@
 @NodeInfo
 public abstract class CompareNode extends BinaryOpLogicNode {
 
+    public static final NodeClass<CompareNode> TYPE = NodeClass.create(CompareNode.class);
     protected final Condition condition;
     protected final boolean unorderedIsTrue;
 
@@ -48,8 +50,8 @@
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
-    public CompareNode(Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
-        super(x, y);
+    protected CompareNode(NodeClass<? extends CompareNode> c, Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
+        super(c, x, y);
         this.condition = condition;
         this.unorderedIsTrue = unorderedIsTrue;
     }
@@ -88,7 +90,7 @@
                     return conditionalNode.condition();
                 } else {
                     assert falseResult == true;
-                    return new LogicNegationNode(conditionalNode.condition());
+                    return LogicNegationNode.create(conditionalNode.condition());
 
                 }
             }
@@ -165,32 +167,33 @@
         return null;
     }
 
-    public static CompareNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
-        return graph.unique(createCompareNode(condition, x, y));
+    public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
+        LogicNode result = createCompareNode(condition, x, y, constantReflection);
+        return (result.graph() == null ? graph.unique(result) : result);
     }
 
-    public static CompareNode createCompareNode(Condition condition, ValueNode x, ValueNode y) {
+    public static LogicNode createCompareNode(Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
         assert x.getKind() == y.getKind();
         assert condition.isCanonical() : "condition is not canonical: " + condition;
         assert !x.getKind().isNumericFloat();
 
-        CompareNode comparison;
+        LogicNode comparison;
         if (condition == Condition.EQ) {
             if (x.stamp() instanceof AbstractObjectStamp) {
-                comparison = new ObjectEqualsNode(x, y);
+                comparison = ObjectEqualsNode.create(x, y, constantReflection);
             } else if (x.stamp() instanceof AbstractPointerStamp) {
                 comparison = new PointerEqualsNode(x, y);
             } else {
                 assert x.getKind().isNumericInteger();
-                comparison = new IntegerEqualsNode(x, y);
+                comparison = IntegerEqualsNode.create(x, y, constantReflection);
             }
         } else if (condition == Condition.LT) {
             assert x.getKind().isNumericInteger();
-            comparison = new IntegerLessThanNode(x, y);
+            comparison = IntegerLessThanNode.create(x, y, constantReflection);
         } else {
             assert condition == Condition.BT;
             assert x.getKind().isNumericInteger();
-            comparison = new IntegerBelowNode(x, y);
+            comparison = IntegerBelowNode.create(x, y, constantReflection);
         }
 
         return comparison;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 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.*;
@@ -40,6 +41,7 @@
 @NodeInfo
 public final class ConditionalNode extends FloatingNode implements Canonicalizable, LIRLowerable {
 
+    public static final NodeClass<ConditionalNode> TYPE = NodeClass.create(ConditionalNode.class);
     @Input(InputType.Condition) LogicNode condition;
     @Input ValueNode trueValue;
     @Input ValueNode falseValue;
@@ -53,13 +55,25 @@
     }
 
     public ConditionalNode(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
-        super(trueValue.stamp().meet(falseValue.stamp()));
+        super(TYPE, trueValue.stamp().meet(falseValue.stamp()));
         assert trueValue.stamp().isCompatible(falseValue.stamp());
         this.condition = condition;
         this.trueValue = trueValue;
         this.falseValue = falseValue;
     }
 
+    public static ValueNode create(LogicNode condition) {
+        return create(condition, ConstantNode.forInt(1, condition.graph()), ConstantNode.forInt(0, condition.graph()));
+    }
+
+    public static ValueNode create(LogicNode condition, ValueNode trueValue, ValueNode falseValue) {
+        ValueNode synonym = findSynonym(condition, trueValue, falseValue);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new ConditionalNode(condition, trueValue, falseValue);
+    }
+
     @Override
     public boolean inferStamp() {
         return updateStamp(trueValue.stamp().meet(falseValue.stamp()));
@@ -75,9 +89,9 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (condition instanceof LogicNegationNode) {
-            LogicNegationNode negated = (LogicNegationNode) condition;
-            return new ConditionalNode(negated.getValue(), falseValue(), trueValue());
+        ValueNode synonym = findSynonym(condition, trueValue(), falseValue());
+        if (synonym != null) {
+            return synonym;
         }
 
         // this optimizes the case where a value that can only be 0 or 1 is materialized to 0 or 1
@@ -92,14 +106,6 @@
                 }
             }
         }
-        if (condition instanceof LogicConstantNode) {
-            LogicConstantNode c = (LogicConstantNode) condition;
-            if (c.getValue()) {
-                return trueValue();
-            } else {
-                return falseValue();
-            }
-        }
         if (condition instanceof CompareNode && ((CompareNode) condition).condition() == Condition.EQ) {
             // optimize the pattern (x == y) ? x : y
             CompareNode compare = (CompareNode) condition;
@@ -114,13 +120,29 @@
         return this;
     }
 
+    private static ValueNode findSynonym(ValueNode condition, ValueNode trueValue, ValueNode falseValue) {
+        if (condition instanceof LogicNegationNode) {
+            LogicNegationNode negated = (LogicNegationNode) condition;
+            return ConditionalNode.create(negated.getValue(), falseValue, trueValue);
+        }
+        if (condition instanceof LogicConstantNode) {
+            LogicConstantNode c = (LogicConstantNode) condition;
+            if (c.getValue()) {
+                return trueValue;
+            } else {
+                return falseValue;
+            }
+        }
+        return null;
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool generator) {
         generator.emitConditional(this);
     }
 
     public ConditionalNode(@InjectedNodeParameter StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
-        this(createCompareNode(graph, condition, x, y));
+        this(createCompareNode(graph, condition, x, y, null));
     }
 
     public ConditionalNode(ValueNode type, ValueNode object) {
@@ -137,4 +159,24 @@
     public static boolean materializeIsInstance(Class<?> mirror, Object object) {
         return mirror.isInstance(object);
     }
+
+    /**
+     * @param thisClass
+     * @param otherClass
+     * @param dummy a marker to make this constructor unique for the
+     *            {@link #materializeIsAssignableFrom(Class, Class, int)} NodeIntrinsic
+     */
+    public ConditionalNode(ValueNode thisClass, ValueNode otherClass, int dummy) {
+        this(thisClass.graph().unique(new ClassIsAssignableFromNode(thisClass, otherClass)));
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    private static boolean materializeIsAssignableFrom(Class<?> thisClass, Class<?> otherClass, @ConstantNodeParameter int dummy) {
+        return thisClass.isAssignableFrom(otherClass);
+    }
+
+    public static boolean materializeIsAssignableFrom(Class<?> thisClass, Class<?> otherClass) {
+        return materializeIsAssignableFrom(thisClass, otherClass, 0);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,7 +25,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Div;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,8 +37,21 @@
 @NodeInfo(shortName = "/")
 public final class DivNode extends BinaryArithmeticNode<Div> {
 
+    public static final NodeClass<DivNode> TYPE = NodeClass.create(DivNode.class);
+
     public DivNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getDiv, x, y);
+        super(TYPE, ArithmeticOpTable::getDiv, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Div> op = ArithmeticOpTable.forStamp(x.stamp()).getDiv();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new DivNode(x, y);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,18 +23,20 @@
 package com.oracle.graal.nodes.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.*;
 
 @NodeInfo
 public abstract class FixedBinaryNode extends DeoptimizingFixedWithNextNode implements Canonicalizable.Binary<ValueNode> {
+    public static final NodeClass<FixedBinaryNode> TYPE = NodeClass.create(FixedBinaryNode.class);
 
     @Input protected ValueNode x;
     @Input protected ValueNode y;
 
-    public FixedBinaryNode(Stamp stamp, ValueNode x, ValueNode y) {
-        super(stamp);
+    public FixedBinaryNode(NodeClass<? extends FixedBinaryNode> c, Stamp stamp, ValueNode x, ValueNode y) {
+        super(c, stamp);
         this.x = x;
         this.y = y;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.FloatConvertOp;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -38,14 +39,23 @@
  */
 @NodeInfo
 public final class FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ConvertNode, Lowerable, ArithmeticLIRLowerable {
+    public static final NodeClass<FloatConvertNode> TYPE = NodeClass.create(FloatConvertNode.class);
 
     protected final FloatConvert op;
 
     public FloatConvertNode(FloatConvert op, ValueNode input) {
-        super(table -> table.getFloatConvert(op), input);
+        super(TYPE, table -> table.getFloatConvert(op), input);
         this.op = op;
     }
 
+    public static ValueNode create(FloatConvert op, ValueNode input) {
+        ValueNode synonym = findSynonym(input, ArithmeticOpTable.forStamp(input.stamp()).getFloatConvert(op));
+        if (synonym != null) {
+            return synonym;
+        }
+        return new FloatConvertNode(op, input);
+    }
+
     public FloatConvert getFloatConvert() {
         return op;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 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.*;
@@ -33,9 +34,10 @@
 
 @NodeInfo(shortName = "==")
 public final class FloatEqualsNode extends CompareNode {
+    public static final NodeClass<FloatEqualsNode> TYPE = NodeClass.create(FloatEqualsNode.class);
 
     public FloatEqualsNode(ValueNode x, ValueNode y) {
-        super(Condition.EQ, false, x, y);
+        super(TYPE, Condition.EQ, false, x, y);
         assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp : x.stamp() + " " + y.stamp();
         assert x.stamp().isCompatible(y.stamp());
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,23 +22,35 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 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.util.*;
 
 @NodeInfo(shortName = "<")
-public class FloatLessThanNode extends CompareNode {
+public final class FloatLessThanNode extends CompareNode {
+    public static final NodeClass<FloatLessThanNode> TYPE = NodeClass.create(FloatLessThanNode.class);
 
     public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
-        super(Condition.LT, unorderedIsTrue, x, y);
+        super(TYPE, Condition.LT, unorderedIsTrue, x, y);
         assert x.stamp() instanceof FloatStamp && y.stamp() instanceof FloatStamp;
         assert x.stamp().isCompatible(y.stamp());
     }
 
+    public static LogicNode create(ValueNode x, ValueNode y, boolean unorderedIsTrue, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, unorderedIsTrue);
+        if (result != null) {
+            return result;
+        } else {
+            return new FloatLessThanNode(x, y, unorderedIsTrue);
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         ValueNode result = super.canonical(tool, forX, forY);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -29,9 +29,10 @@
 
 @NodeInfo
 public abstract class FloatingNode extends ValueNode implements Node.ValueNumberable {
+    public static final NodeClass<FloatingNode> TYPE = NodeClass.create(FloatingNode.class);
 
-    public FloatingNode(Stamp stamp) {
-        super(stamp);
+    public FloatingNode(NodeClass<? extends FloatingNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,16 +25,18 @@
 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.util.*;
 
 @NodeInfo(shortName = "|<|")
-public class IntegerBelowNode extends CompareNode {
+public final class IntegerBelowNode extends CompareNode {
+    public static final NodeClass<IntegerBelowNode> TYPE = NodeClass.create(IntegerBelowNode.class);
 
     public IntegerBelowNode(ValueNode x, ValueNode y) {
-        super(Condition.BT, false, x, y);
+        super(TYPE, Condition.BT, false, x, y);
         assert x.stamp() instanceof IntegerStamp;
         assert y.stamp() instanceof IntegerStamp;
     }
@@ -64,7 +66,7 @@
         }
         if (forX.isConstant() && forX.asJavaConstant().asLong() == 0) {
             // 0 |<| y is the same as 0 != y
-            return new LogicNegationNode(CompareNode.createCompareNode(Condition.EQ, forX, forY));
+            return LogicNegationNode.create(CompareNode.createCompareNode(Condition.EQ, forX, forY, tool.getConstantReflection()));
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -38,6 +39,7 @@
  */
 @NodeInfo
 public abstract class IntegerConvertNode<OP, REV> extends UnaryNode implements ConvertNode, ArithmeticLIRLowerable {
+    @SuppressWarnings("rawtypes") public static final NodeClass<IntegerConvertNode> TYPE = NodeClass.create(IntegerConvertNode.class);
 
     protected final SerializableIntegerConvertFunction<OP> getOp;
     protected final SerializableIntegerConvertFunction<REV> getReverseOp;
@@ -48,8 +50,9 @@
     protected interface SerializableIntegerConvertFunction<T> extends Function<ArithmeticOpTable, IntegerConvertOp<T>>, Serializable {
     }
 
-    protected IntegerConvertNode(SerializableIntegerConvertFunction<OP> getOp, SerializableIntegerConvertFunction<REV> getReverseOp, int inputBits, int resultBits, ValueNode input) {
-        super(getOp.apply(ArithmeticOpTable.forStamp(input.stamp())).foldStamp(inputBits, resultBits, input.stamp()), input);
+    protected IntegerConvertNode(NodeClass<? extends IntegerConvertNode<OP, REV>> c, SerializableIntegerConvertFunction<OP> getOp, SerializableIntegerConvertFunction<REV> getReverseOp, int inputBits,
+                    int resultBits, ValueNode input) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(input.stamp())).foldStamp(inputBits, resultBits, input.stamp()), input);
         this.getOp = getOp;
         this.getReverseOp = getReverseOp;
         this.inputBits = inputBits;
@@ -86,13 +89,20 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode synonym = findSynonym(getOp(forValue), forValue, inputBits, resultBits, stamp());
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+    protected static <T> ValueNode findSynonym(IntegerConvertOp<T> operation, ValueNode value, int inputBits, int resultBits, Stamp stamp) {
         if (inputBits == resultBits) {
             return value;
         } else if (value.isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()));
-        } else {
-            return this;
+            return ConstantNode.forPrimitive(stamp, operation.foldConstant(inputBits, resultBits, value.asConstant()));
         }
+        return null;
     }
 
     public static ValueNode convert(ValueNode input, Stamp stamp) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -33,10 +33,11 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "/")
-public class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public final class IntegerDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+    public static final NodeClass<IntegerDivNode> TYPE = NodeClass.create(IntegerDivNode.class);
 
     public IntegerDivNode(ValueNode x, ValueNode y) {
-        super(IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y);
+        super(TYPE, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
@@ -94,7 +95,7 @@
         }
 
         if (next() instanceof IntegerDivNode) {
-            NodeClass nodeClass = getNodeClass();
+            NodeClass<?> nodeClass = getNodeClass();
             if (next().getClass() == this.getClass() && nodeClass.getEdges(Inputs).areEqualIn(this, next()) && valueEquals(next())) {
                 return next();
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 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.*;
@@ -33,9 +34,10 @@
 
 @NodeInfo(shortName = "==")
 public final class IntegerEqualsNode extends CompareNode {
+    public static final NodeClass<IntegerEqualsNode> TYPE = NodeClass.create(IntegerEqualsNode.class);
 
     public IntegerEqualsNode(ValueNode x, ValueNode y) {
-        super(Condition.EQ, false, x, y);
+        super(TYPE, Condition.EQ, false, x, y);
         assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
         assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
@@ -45,6 +47,24 @@
         if (result != null) {
             return result;
         } else {
+            if (x instanceof ConditionalNode) {
+                ConditionalNode conditionalNode = (ConditionalNode) x;
+                if (conditionalNode.trueValue() == y) {
+                    return conditionalNode.condition();
+                }
+                if (conditionalNode.falseValue() == y) {
+                    return LogicNegationNode.create(conditionalNode.condition());
+                }
+            } else if (y instanceof ConditionalNode) {
+                ConditionalNode conditionalNode = (ConditionalNode) y;
+                if (conditionalNode.trueValue() == x) {
+                    return conditionalNode.condition();
+                }
+                if (conditionalNode.falseValue() == x) {
+                    return LogicNegationNode.create(conditionalNode.condition());
+                }
+            }
+
             return new IntegerEqualsNode(x, y);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,16 +26,18 @@
 import com.oracle.graal.compiler.common.*;
 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.util.*;
 
 @NodeInfo(shortName = "<")
-public class IntegerLessThanNode extends CompareNode {
+public final class IntegerLessThanNode extends CompareNode {
+    public static final NodeClass<IntegerLessThanNode> TYPE = NodeClass.create(IntegerLessThanNode.class);
 
     public IntegerLessThanNode(ValueNode x, ValueNode y) {
-        super(Condition.LT, false, x, y);
+        super(TYPE, Condition.LT, false, x, y);
         assert !x.getKind().isNumericFloat() && x.getKind() != Kind.Object;
         assert !y.getKind().isNumericFloat() && y.getKind() != Kind.Object;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,16 +24,18 @@
 
 import com.oracle.graal.api.code.*;
 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.spi.*;
 
 @NodeInfo(shortName = "%")
-public class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public final class IntegerRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+    public static final NodeClass<IntegerRemNode> TYPE = NodeClass.create(IntegerRemNode.class);
 
     public IntegerRemNode(ValueNode x, ValueNode y) {
-        super(IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y);
+        super(TYPE, IntegerStamp.OPS.getRem().foldStamp(x.stamp(), y.stamp()), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.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.*;
@@ -33,10 +34,11 @@
  * both x and y.
  */
 @NodeInfo
-public class IntegerTestNode extends BinaryOpLogicNode {
+public final class IntegerTestNode extends BinaryOpLogicNode {
+    public static final NodeClass<IntegerTestNode> TYPE = NodeClass.create(IntegerTestNode.class);
 
     public IntegerTestNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(TYPE, x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.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.*;
@@ -33,10 +34,12 @@
  * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
  */
 @NodeInfo
-public class IsNullNode extends UnaryOpLogicNode implements LIRLowerable, Virtualizable, PiPushable {
+public final class IsNullNode extends UnaryOpLogicNode implements LIRLowerable, Virtualizable, PiPushable {
+
+    public static final NodeClass<IsNullNode> TYPE = NodeClass.create(IsNullNode.class);
 
     public IsNullNode(ValueNode object) {
-        super(object);
+        super(TYPE, object);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shl;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -32,10 +33,12 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "<<")
-public class LeftShiftNode extends ShiftNode<Shl> {
+public final class LeftShiftNode extends ShiftNode<Shl> {
+
+    public static final NodeClass<LeftShiftNode> TYPE = NodeClass.create(LeftShiftNode.class);
 
     public LeftShiftNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getShl, x, y);
+        super(TYPE, ArithmeticOpTable::getShl, x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 +26,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Mul;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -36,8 +37,25 @@
 @NodeInfo(shortName = "*")
 public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode {
 
+    public static final NodeClass<MulNode> TYPE = NodeClass.create(MulNode.class);
+
     public MulNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getMul, x, y);
+        this(TYPE, x, y);
+    }
+
+    protected MulNode(NodeClass<? extends MulNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getMul, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Mul> op = ArithmeticOpTable.forStamp(x.stamp()).getMul();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new MulNode(x, y);
+        }
     }
 
     @Override
@@ -59,33 +77,8 @@
 
             if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getKind().isNumericInteger()) {
                 long i = ((PrimitiveConstant) c).asLong();
-                boolean signFlip = false;
-                if (i < 0) {
-                    i = -i;
-                    signFlip = true;
-                }
-                if (i > 0) {
-                    ValueNode mulResult = null;
-                    long bit1 = i & -i;
-                    long bit2 = i - bit1;
-                    bit2 = bit2 & -bit2;    // Extract 2nd bit
-                    if (CodeUtil.isPowerOf2(i)) { //
-                        mulResult = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i)));
-                    } else if (bit2 + bit1 == i) { // We can work with two shifts and add
-                        ValueNode shift1 = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(bit1)));
-                        ValueNode shift2 = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(bit2)));
-                        mulResult = new AddNode(shift1, shift2);
-                    } else if (CodeUtil.isPowerOf2(i + 1)) { // shift and subtract
-                        ValueNode shift1 = new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i + 1)));
-                        mulResult = new SubNode(shift1, forX);
-                    }
-                    if (mulResult != null) {
-                        if (signFlip) {
-                            return new NegateNode(mulResult);
-                        } else {
-                            return mulResult;
-                        }
-                    }
+                if (i > 0 && CodeUtil.isPowerOf2(i)) {
+                    return new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i)));
                 }
             }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Sat Feb 21 19:55:33 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
@@ -23,8 +23,10 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -37,13 +39,29 @@
 @NodeInfo
 public final class NarrowNode extends IntegerConvertNode<Narrow, SignExtend> {
 
+    public static final NodeClass<NarrowNode> TYPE = NodeClass.create(NarrowNode.class);
+
     public NarrowNode(ValueNode input, int resultBits) {
         this(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
         assert 0 < resultBits && resultBits <= PrimitiveStamp.getBits(input.stamp());
     }
 
     public NarrowNode(ValueNode input, int inputBits, int resultBits) {
-        super(ArithmeticOpTable::getNarrow, ArithmeticOpTable::getSignExtend, inputBits, resultBits, input);
+        super(TYPE, ArithmeticOpTable::getNarrow, ArithmeticOpTable::getSignExtend, inputBits, resultBits, input);
+    }
+
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<Narrow> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getNarrow();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new NarrowNode(input, inputBits, resultBits);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Neg;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -36,8 +37,10 @@
 @NodeInfo
 public final class NegateNode extends UnaryArithmeticNode<Neg> implements NarrowableArithmeticNode {
 
+    public static final NodeClass<NegateNode> TYPE = NodeClass.create(NegateNode.class);
+
     public NegateNode(ValueNode value) {
-        super(ArithmeticOpTable::getNeg, value);
+        super(TYPE, ArithmeticOpTable::getNeg, value);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,7 +23,9 @@
 package com.oracle.graal.nodes.calc;
 
 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.*;
@@ -35,15 +37,36 @@
  * true.
  */
 @NodeInfo
-public class NormalizeCompareNode extends BinaryNode implements Lowerable {
+public final class NormalizeCompareNode extends BinaryNode implements Lowerable {
 
+    public static final NodeClass<NormalizeCompareNode> TYPE = NodeClass.create(NormalizeCompareNode.class);
     protected final boolean isUnorderedLess;
 
     public NormalizeCompareNode(ValueNode x, ValueNode y, boolean isUnorderedLess) {
-        super(StampFactory.forKind(Kind.Int), x, y);
+        super(TYPE, StampFactory.forKind(Kind.Int), x, y);
         this.isUnorderedLess = isUnorderedLess;
     }
 
+    public static ValueNode create(ValueNode x, ValueNode y, boolean isUnorderedLess, ConstantReflectionProvider constantReflection) {
+        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        if (result instanceof LogicConstantNode) {
+            LogicConstantNode logicConstantNode = (LogicConstantNode) result;
+            LogicNode resultLT = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, isUnorderedLess);
+            if (resultLT instanceof LogicConstantNode) {
+                LogicConstantNode logicConstantNodeLT = (LogicConstantNode) resultLT;
+                if (logicConstantNodeLT.getValue()) {
+                    return ConstantNode.forInt(-1);
+                } else if (logicConstantNode.getValue()) {
+                    return ConstantNode.forInt(0);
+                } else {
+                    return ConstantNode.forInt(1);
+                }
+            }
+        }
+
+        return new NormalizeCompareNode(x, y, isUnorderedLess);
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         // nothing to do
@@ -56,10 +79,10 @@
         LogicNode lessComp;
         if (getX().stamp() instanceof FloatStamp) {
             equalComp = graph().unique(FloatEqualsNode.create(getX(), getY(), tool.getConstantReflection()));
-            lessComp = graph().unique(new FloatLessThanNode(getX(), getY(), isUnorderedLess));
+            lessComp = graph().unique(FloatLessThanNode.create(getX(), getY(), isUnorderedLess, tool.getConstantReflection()));
         } else {
-            equalComp = graph().unique(new IntegerEqualsNode(getX(), getY()));
-            lessComp = graph().unique(new IntegerLessThanNode(getX(), getY()));
+            equalComp = graph().unique(IntegerEqualsNode.create(getX(), getY(), tool.getConstantReflection()));
+            lessComp = graph().unique(IntegerLessThanNode.create(getX(), getY(), tool.getConstantReflection()));
         }
 
         ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph())));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Not;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,10 +35,12 @@
  * Binary negation of long or integer values.
  */
 @NodeInfo
-public class NotNode extends UnaryArithmeticNode<Not> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public final class NotNode extends UnaryArithmeticNode<Not> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+
+    public static final NodeClass<NotNode> TYPE = NodeClass.create(NotNode.class);
 
     public NotNode(ValueNode x) {
-        super(ArithmeticOpTable::getNot, x);
+        super(TYPE, ArithmeticOpTable::getNot, x);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,8 +34,10 @@
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable {
 
+    public static final NodeClass<ObjectEqualsNode> TYPE = NodeClass.create(ObjectEqualsNode.class);
+
     public ObjectEqualsNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(TYPE, x, y);
         assert x.stamp() instanceof AbstractObjectStamp;
         assert y.stamp() instanceof AbstractObjectStamp;
     }
@@ -89,7 +92,7 @@
                 /*
                  * One of the two objects has identity, the other doesn't. In code, this looks like
                  * "Integer.valueOf(a) == new Integer(b)", which is always false.
-                 * 
+                 *
                  * In other words: an object created via valueOf can never be equal to one created
                  * by new in the same compilation unit.
                  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 +25,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Or;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,10 +36,23 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|")
-public class OrNode extends BinaryArithmeticNode<Or> {
+public final class OrNode extends BinaryArithmeticNode<Or> {
+
+    public static final NodeClass<OrNode> TYPE = NodeClass.create(OrNode.class);
 
     public OrNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getOr, x, y);
+        super(TYPE, ArithmeticOpTable::getOr, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Or> op = ArithmeticOpTable.forStamp(x.stamp()).getOr();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new OrNode(x, y);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 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.*;
@@ -32,8 +33,14 @@
 @NodeInfo(shortName = "==")
 public class PointerEqualsNode extends CompareNode {
 
+    public static final NodeClass<PointerEqualsNode> TYPE = NodeClass.create(PointerEqualsNode.class);
+
     public PointerEqualsNode(ValueNode x, ValueNode y) {
-        super(Condition.EQ, false, x, y);
+        this(TYPE, x, y);
+    }
+
+    protected PointerEqualsNode(NodeClass<? extends PointerEqualsNode> c, ValueNode x, ValueNode y) {
+        super(c, Condition.EQ, false, x, y);
         assert x.stamp() instanceof AbstractPointerStamp;
         assert y.stamp() instanceof AbstractPointerStamp;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -38,14 +39,16 @@
  * the old stamp.
  */
 @NodeInfo
-public class ReinterpretNode extends UnaryNode implements ArithmeticLIRLowerable {
+public final class ReinterpretNode extends UnaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<ReinterpretNode> TYPE = NodeClass.create(ReinterpretNode.class);
 
     public ReinterpretNode(Kind to, ValueNode value) {
         this(StampFactory.forKind(to), value);
     }
 
     public ReinterpretNode(Stamp to, ValueNode value) {
-        super(to, value);
+        super(TYPE, to, value);
         assert to instanceof ArithmeticStamp;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,16 +24,19 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Rem;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "%")
-public class RemNode extends BinaryArithmeticNode<Rem> implements Lowerable {
+public final class RemNode extends BinaryArithmeticNode<Rem> implements Lowerable {
+
+    public static final NodeClass<RemNode> TYPE = NodeClass.create(RemNode.class);
 
     public RemNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getRem, x, y);
+        super(TYPE, ArithmeticOpTable::getRem, x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.Shr;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -31,10 +32,12 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = ">>")
-public class RightShiftNode extends ShiftNode<Shr> {
+public final class RightShiftNode extends ShiftNode<Shr> {
+
+    public static final NodeClass<RightShiftNode> TYPE = NodeClass.create(RightShiftNode.class);
 
     public RightShiftNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getShr, x, y);
+        super(TYPE, ArithmeticOpTable::getShr, x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,6 +28,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -39,6 +40,8 @@
 @NodeInfo
 public abstract class ShiftNode<OP> extends BinaryNode implements ArithmeticLIRLowerable {
 
+    @SuppressWarnings("rawtypes") public static final NodeClass<ShiftNode> TYPE = NodeClass.create(ShiftNode.class);
+
     protected interface SerializableShiftFunction<T> extends Function<ArithmeticOpTable, ShiftOp<T>>, Serializable {
     }
 
@@ -50,8 +53,8 @@
      * @param x the first input value
      * @param s the second input value
      */
-    public ShiftNode(SerializableShiftFunction<OP> getOp, ValueNode x, ValueNode s) {
-        super(getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), (IntegerStamp) s.stamp()), x, s);
+    protected ShiftNode(NodeClass<? extends ShiftNode<OP>> c, SerializableShiftFunction<OP> getOp, ValueNode x, ValueNode s) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(x.stamp())).foldStamp(x.stamp(), (IntegerStamp) s.stamp()), x, s);
         assert ((IntegerStamp) s.stamp()).getBits() == 32;
         this.getOp = getOp;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Sat Feb 21 19:55:33 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
@@ -23,8 +23,10 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.SignExtend;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,7 +37,9 @@
  * The {@code SignExtendNode} converts an integer to a wider integer using sign extension.
  */
 @NodeInfo
-public class SignExtendNode extends IntegerConvertNode<SignExtend, Narrow> {
+public final class SignExtendNode extends IntegerConvertNode<SignExtend, Narrow> {
+
+    public static final NodeClass<SignExtendNode> TYPE = NodeClass.create(SignExtendNode.class);
 
     public SignExtendNode(ValueNode input, int resultBits) {
         this(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
@@ -43,7 +47,21 @@
     }
 
     public SignExtendNode(ValueNode input, int inputBits, int resultBits) {
-        super(ArithmeticOpTable::getSignExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+        super(TYPE, ArithmeticOpTable::getSignExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+    }
+
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<SignExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getSignExtend();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new SignExtendNode(input, inputBits, resultBits);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -33,10 +34,12 @@
  * Square root.
  */
 @NodeInfo
-public class SqrtNode extends UnaryArithmeticNode<Sqrt> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+public final class SqrtNode extends UnaryArithmeticNode<Sqrt> implements ArithmeticLIRLowerable, NarrowableArithmeticNode {
+
+    public static final NodeClass<SqrtNode> TYPE = NodeClass.create(SqrtNode.class);
 
     public SqrtNode(ValueNode x) {
-        super(ArithmeticOpTable::getSqrt, x);
+        super(TYPE, ArithmeticOpTable::getSqrt, x);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 +25,8 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Sub;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -36,8 +37,25 @@
 @NodeInfo(shortName = "-")
 public class SubNode extends BinaryArithmeticNode<Sub> implements NarrowableArithmeticNode {
 
+    public static final NodeClass<SubNode> TYPE = NodeClass.create(SubNode.class);
+
     public SubNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getSub, x, y);
+        this(TYPE, x, y);
+    }
+
+    protected SubNode(NodeClass<? extends SubNode> c, ValueNode x, ValueNode y) {
+        super(c, ArithmeticOpTable::getSub, x, y);
+    }
+
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Sub> op = ArithmeticOpTable.forStamp(x.stamp()).getSub();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new SubNode(x, y);
+        }
     }
 
     @SuppressWarnings("hiding")
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 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
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.UnaryOp;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -35,13 +36,15 @@
 @NodeInfo
 public abstract class UnaryArithmeticNode<OP> extends UnaryNode implements ArithmeticLIRLowerable {
 
+    @SuppressWarnings("rawtypes") public static final NodeClass<UnaryArithmeticNode> TYPE = NodeClass.create(UnaryArithmeticNode.class);
+
     protected interface SerializableUnaryFunction<T> extends Function<ArithmeticOpTable, UnaryOp<T>>, Serializable {
     }
 
     protected final SerializableUnaryFunction<OP> getOp;
 
-    protected UnaryArithmeticNode(SerializableUnaryFunction<OP> getOp, ValueNode value) {
-        super(getOp.apply(ArithmeticOpTable.forStamp(value.stamp())).foldStamp(value.stamp()), value);
+    protected UnaryArithmeticNode(NodeClass<? extends UnaryArithmeticNode<OP>> c, SerializableUnaryFunction<OP> getOp, ValueNode value) {
+        super(c, getOp.apply(ArithmeticOpTable.forStamp(value.stamp())).foldStamp(value.stamp()), value);
         this.getOp = getOp;
     }
 
@@ -56,9 +59,17 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
-        if (forValue.isConstant()) {
-            return ConstantNode.forPrimitive(stamp(), getOp(forValue).foldConstant(forValue.asConstant()));
+        ValueNode synonym = findSynonym(forValue, getOp(forValue));
+        if (synonym != null) {
+            return synonym;
         }
         return this;
     }
+
+    protected static <OP> ValueNode findSynonym(ValueNode forValue, UnaryOp<OP> op) {
+        if (forValue.isConstant()) {
+            return ConstantNode.forPrimitive(op.foldStamp(forValue.stamp()), op.foldConstant(forValue.asConstant()));
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.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.*;
@@ -34,6 +35,7 @@
 @NodeInfo
 public abstract class UnaryNode extends FloatingNode implements Canonicalizable.Unary<ValueNode> {
 
+    public static final NodeClass<UnaryNode> TYPE = NodeClass.create(UnaryNode.class);
     @Input protected ValueNode value;
 
     public ValueNode getValue() {
@@ -46,8 +48,8 @@
      * @param stamp the result type of this instruction
      * @param value the input instruction
      */
-    public UnaryNode(Stamp stamp, ValueNode value) {
-        super(stamp);
+    protected UnaryNode(NodeClass<? extends UnaryNode> c, Stamp stamp, ValueNode value) {
+        super(c, stamp);
         this.value = value;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,16 +24,19 @@
 
 import com.oracle.graal.api.code.*;
 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.spi.*;
 
 @NodeInfo(shortName = "|/|")
-public class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public final class UnsignedDivNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+
+    public static final NodeClass<UnsignedDivNode> TYPE = NodeClass.create(UnsignedDivNode.class);
 
     public UnsignedDivNode(ValueNode x, ValueNode y) {
-        super(x.stamp().unrestricted(), x, y);
+        super(TYPE, x.stamp().unrestricted(), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,16 +24,19 @@
 
 import com.oracle.graal.api.code.*;
 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.spi.*;
 
 @NodeInfo(shortName = "|%|")
-public class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+public final class UnsignedRemNode extends FixedBinaryNode implements Lowerable, LIRLowerable {
+
+    public static final NodeClass<UnsignedRemNode> TYPE = NodeClass.create(UnsignedRemNode.class);
 
     public UnsignedRemNode(ValueNode x, ValueNode y) {
-        super(x.stamp().unrestricted(), x, y);
+        super(TYPE, x.stamp().unrestricted(), x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.ShiftOp.UShr;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -32,10 +33,12 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = ">>>")
-public class UnsignedRightShiftNode extends ShiftNode<UShr> {
+public final class UnsignedRightShiftNode extends ShiftNode<UShr> {
+
+    public static final NodeClass<UnsignedRightShiftNode> TYPE = NodeClass.create(UnsignedRightShiftNode.class);
 
     public UnsignedRightShiftNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getUShr, x, y);
+        super(TYPE, ArithmeticOpTable::getUShr, x, y);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 +25,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Xor;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,13 +36,26 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "^")
-public class XorNode extends BinaryArithmeticNode<Xor> {
+public final class XorNode extends BinaryArithmeticNode<Xor> {
+
+    public static final NodeClass<XorNode> TYPE = NodeClass.create(XorNode.class);
 
     public XorNode(ValueNode x, ValueNode y) {
-        super(ArithmeticOpTable::getXor, x, y);
+        super(TYPE, ArithmeticOpTable::getXor, x, y);
         assert x.stamp().isCompatible(y.stamp());
     }
 
+    public static ValueNode create(ValueNode x, ValueNode y) {
+        BinaryOp<Xor> op = ArithmeticOpTable.forStamp(x.stamp()).getXor();
+        Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+        ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+        if (tryConstantFold != null) {
+            return tryConstantFold;
+        } else {
+            return new XorNode(x, y);
+        }
+    }
+
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         ValueNode ret = super.canonical(tool, forX, forY);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Sat Feb 21 19:55:33 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
@@ -25,8 +25,9 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
-import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.ZeroExtend;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.*;
+import com.oracle.graal.compiler.common.type.ArithmeticOpTable.IntegerConvertOp.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -37,7 +38,9 @@
  * The {@code ZeroExtendNode} converts an integer to a wider integer using zero extension.
  */
 @NodeInfo
-public class ZeroExtendNode extends IntegerConvertNode<ZeroExtend, Narrow> {
+public final class ZeroExtendNode extends IntegerConvertNode<ZeroExtend, Narrow> {
+
+    public static final NodeClass<ZeroExtendNode> TYPE = NodeClass.create(ZeroExtendNode.class);
 
     public ZeroExtendNode(ValueNode input, int resultBits) {
         this(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
@@ -45,7 +48,21 @@
     }
 
     public ZeroExtendNode(ValueNode input, int inputBits, int resultBits) {
-        super(ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+        super(TYPE, ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+    }
+
+    public static ValueNode create(ValueNode input, int resultBits) {
+        return create(input, PrimitiveStamp.getBits(input.stamp()), resultBits);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits) {
+        IntegerConvertOp<ZeroExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp()).getZeroExtend();
+        ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp()));
+        if (synonym != null) {
+            return synonym;
+        } else {
+            return new ZeroExtendNode(input, inputBits, resultBits);
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Sat Feb 21 19:55:33 2015 +0100
@@ -118,48 +118,45 @@
         return loops;
     }
 
-    public void clearNodeToBlock() {
-        nodeToBlock.clear();
-        for (Block block : reversePostOrder) {
-            identifyBlock(block);
-        }
-    }
-
     private void identifyBlock(Block block) {
-        Node cur = block.getBeginNode();
-        Node last;
+        AbstractBeginNode start = block.getBeginNode();
 
         // assign proxies of a loop exit to this block
-        if (cur instanceof AbstractBeginNode) {
-            for (Node usage : cur.usages()) {
+        if (start instanceof LoopExitNode) {
+            for (Node usage : start.usages()) {
                 if (usage instanceof ProxyNode) {
                     nodeToBlock.set(usage, block);
                 }
             }
+        } else if (start instanceof AbstractMergeNode) {
+            for (PhiNode phi : ((AbstractMergeNode) start).phis()) {
+                nodeToBlock.set(phi, block);
+            }
         }
 
-        do {
+        FixedWithNextNode cur = start;
+        while (true) {
             assert !cur.isDeleted();
-
             assert nodeToBlock.get(cur) == null;
             nodeToBlock.set(cur, block);
-            if (cur instanceof AbstractMergeNode) {
-                for (PhiNode phi : ((AbstractMergeNode) cur).phis()) {
-                    nodeToBlock.set(phi, block);
-                }
+            FixedNode next = cur.next();
+            if (next instanceof AbstractBeginNode) {
+                block.endNode = cur;
+                return;
+            } else if (next instanceof FixedWithNextNode) {
+                cur = (FixedWithNextNode) next;
+            } else {
+                nodeToBlock.set(next, block);
+                block.endNode = next;
+                return;
             }
-
-            last = cur;
-            cur = cur.successors().first();
-        } while (cur != null && !(cur instanceof AbstractBeginNode));
-
-        block.endNode = (FixedNode) last;
+        }
     }
 
     private void identifyBlocks() {
         // Find all block headers
         int numBlocks = 0;
-        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.class)) {
+        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
             Block block = new Block(begin);
             numBlocks++;
             identifyBlock(block);
@@ -203,14 +200,19 @@
     }
 
     // Connect blocks (including loop backward edges), but ignoring dead code (blocks with id < 0).
+    // Predecessors need to be in the order expected when iterating phi inputs.
     private void connectBlocks() {
         for (Block block : reversePostOrder) {
-            List<Block> predecessors = new ArrayList<>(4);
+            List<Block> predecessors = new ArrayList<>(1);
             double probability = block.getBeginNode() instanceof StartNode ? 1D : 0D;
             for (Node predNode : block.getBeginNode().cfgPredecessors()) {
                 Block predBlock = nodeToBlock.get(predNode);
                 if (predBlock.getId() >= 0) {
                     predecessors.add(predBlock);
+                    if (predBlock.getSuccessors() == null) {
+                        predBlock.setSuccessors(new ArrayList<>(1));
+                    }
+                    predBlock.getSuccessors().add(block);
                     probability += predBlock.probability;
                 }
             }
@@ -225,6 +227,10 @@
                     assert predBlock != null : predNode;
                     if (predBlock.getId() >= 0) {
                         predecessors.add(predBlock);
+                        if (predBlock.getSuccessors() == null) {
+                            predBlock.setSuccessors(new ArrayList<>(1));
+                        }
+                        predBlock.getSuccessors().add(block);
                     }
                 }
             }
@@ -233,19 +239,9 @@
             }
             block.setPredecessors(predecessors);
             block.setProbability(probability);
-
-            List<Block> successors = new ArrayList<>(4);
-            for (Node suxNode : block.getEndNode().cfgSuccessors()) {
-                Block suxBlock = nodeToBlock.get(suxNode);
-                assert suxBlock.getId() >= 0;
-                successors.add(suxBlock);
+            if (block.getSuccessors() == null) {
+                block.setSuccessors(new ArrayList<>(1));
             }
-            if (block.getEndNode() instanceof LoopEndNode) {
-                Block suxBlock = nodeToBlock.get(((LoopEndNode) block.getEndNode()).loopBegin());
-                assert suxBlock.getId() >= 0;
-                successors.add(suxBlock);
-            }
-            block.setSuccessors(successors);
         }
     }
 
@@ -269,29 +265,30 @@
                     computeLoopBlocks(exitBlock.getFirstPredecessor(), loop);
                     loop.getExits().add(exitBlock);
                 }
-                List<Block> unexpected = new LinkedList<>();
-                for (Block b : loop.getBlocks()) {
+
+                // The following loop can add new blocks to the end of the loop's block list.
+                int size = loop.getBlocks().size();
+                for (int i = 0; i < size; ++i) {
+                    Block b = loop.getBlocks().get(i);
                     for (Block sux : b.getSuccessors()) {
                         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);
-                                unexpected.add(sux);
+                                Debug.log(3, "Unexpected loop exit with %s, including whole branch in the loop", sux);
+                                addBranchToLoop(loop, sux);
                             }
                         }
                     }
                 }
-                for (Block b : unexpected) {
-                    addBranchToLoop(loop, b);
-                }
             }
         }
     }
 
     private static void addBranchToLoop(Loop<Block> l, Block b) {
-        if (l.getBlocks().contains(b)) {
+        if (b.loop == l) {
             return;
         }
+        assert !(l.getBlocks().contains(b));
         l.getBlocks().add(b);
         b.loop = l;
         for (Block sux : b.getSuccessors()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/BlackholeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/BlackholeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.debug;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -30,10 +31,11 @@
 @NodeInfo
 public final class BlackholeNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<BlackholeNode> TYPE = NodeClass.create(BlackholeNode.class);
     @Input ValueNode value;
 
     public BlackholeNode(ValueNode value) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,7 +33,9 @@
  * control flow anchors.
  */
 @NodeInfo
-public class ControlFlowAnchorNode extends FixedWithNextNode implements LIRLowerable {
+public final class ControlFlowAnchorNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static final NodeClass<ControlFlowAnchorNode> TYPE = NodeClass.create(ControlFlowAnchorNode.class);
 
     private static class Unique {
     }
@@ -41,7 +43,7 @@
     protected Unique unique;
 
     public ControlFlowAnchorNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.unique = new Unique();
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.debug;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -38,6 +39,7 @@
 @NodeInfo
 public class DynamicCounterNode extends FixedWithNextNode implements Lowerable {
 
+    public static final NodeClass<DynamicCounterNode> TYPE = NodeClass.create(DynamicCounterNode.class);
     @Input ValueNode increment;
 
     protected final String name;
@@ -45,7 +47,11 @@
     protected final boolean withContext;
 
     public DynamicCounterNode(String name, String group, ValueNode increment, boolean withContext) {
-        super(StampFactory.forVoid());
+        this(TYPE, name, group, increment, withContext);
+    }
+
+    protected DynamicCounterNode(NodeClass<? extends DynamicCounterNode> c, String name, String group, ValueNode increment, boolean withContext) {
+        super(c, StampFactory.forVoid());
         this.name = name;
         this.group = group;
         this.increment = increment;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/OpaqueNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/OpaqueNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,18 +22,20 @@
  */
 package com.oracle.graal.nodes.debug;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class OpaqueNode extends FloatingNode implements LIRLowerable {
+public final class OpaqueNode extends FloatingNode implements LIRLowerable {
 
+    public static final NodeClass<OpaqueNode> TYPE = NodeClass.create(OpaqueNode.class);
     @Input ValueNode value;
 
     public OpaqueNode(ValueNode value) {
-        super(value.stamp().unrestricted());
+        super(TYPE, value.stamp().unrestricted());
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/VerifyHeapNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/VerifyHeapNode.java	Sat Feb 21 19:55:33 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
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.debug;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -32,10 +33,12 @@
  * heap corruption issues.
  */
 @NodeInfo
-public class VerifyHeapNode extends FixedWithNextNode implements Lowerable {
+public final class VerifyHeapNode extends FixedWithNextNode implements Lowerable {
+
+    public static final NodeClass<VerifyHeapNode> TYPE = NodeClass.create(VerifyHeapNode.class);
 
     public VerifyHeapNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Sat Feb 21 19:55:33 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.debug;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -34,12 +35,13 @@
  * actually executed.
  */
 @NodeInfo
-public class WeakCounterNode extends DynamicCounterNode implements Simplifiable, Virtualizable {
+public final class WeakCounterNode extends DynamicCounterNode implements Simplifiable, Virtualizable {
 
+    public static final NodeClass<WeakCounterNode> TYPE = NodeClass.create(WeakCounterNode.class);
     @Input ValueNode checkedValue;
 
     public WeakCounterNode(String group, String name, ValueNode increment, boolean addContext, ValueNode checkedValue) {
-        super(group, name, increment, addContext);
+        super(TYPE, group, name, increment, addContext);
         this.checkedValue = checkedValue;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,6 +31,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public abstract class AbstractWriteNode extends FixedAccessNode implements StateSplit, MemoryCheckpoint.Single, MemoryAccess, GuardingNode {
 
+    public static final NodeClass<AbstractWriteNode> TYPE = NodeClass.create(AbstractWriteNode.class);
     @Input ValueNode value;
     @OptionalInput(InputType.State) FrameState stateAfter;
     @OptionalInput(InputType.Memory) Node lastLocationAccess;
@@ -64,18 +65,18 @@
         return initialization;
     }
 
-    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
-        this(object, value, location, barrierType, false);
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
+        this(c, object, value, location, barrierType, false);
     }
 
-    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
-        super(object, location, StampFactory.forVoid(), barrierType);
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
+        super(c, object, location, StampFactory.forVoid(), barrierType);
         this.value = value;
         this.initialization = initialization;
     }
 
-    public AbstractWriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
-        super(object, location, StampFactory.forVoid(), guard, barrierType, false, null);
+    protected AbstractWriteNode(NodeClass<? extends AbstractWriteNode> c, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
+        super(c, object, location, StampFactory.forVoid(), guard, barrierType, false, null);
         this.value = value;
         this.initialization = initialization;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -38,6 +39,7 @@
 @NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
 public final class AddLocationNode extends LocationNode implements Canonicalizable.Binary<LocationNode> {
 
+    public static final NodeClass<AddLocationNode> TYPE = NodeClass.create(AddLocationNode.class);
     @Input(InputType.Association) ValueNode x;
     @Input(InputType.Association) ValueNode y;
 
@@ -50,7 +52,7 @@
     }
 
     public AddLocationNode(LocationNode x, LocationNode y) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         assert x.getLocationIdentity().equals(y.getLocationIdentity());
         this.x = x;
         this.y = y;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
@@ -32,8 +33,10 @@
 @NodeInfo
 public abstract class ArrayRangeWriteNode extends AbstractMemoryCheckpoint {
 
-    protected ArrayRangeWriteNode(Stamp stamp) {
-        super(stamp);
+    public static final NodeClass<ArrayRangeWriteNode> TYPE = NodeClass.create(ArrayRangeWriteNode.class);
+
+    protected ArrayRangeWriteNode(NodeClass<? extends ArrayRangeWriteNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -42,10 +43,11 @@
 @NodeInfo
 public final class BoxNode extends UnaryNode implements VirtualizableAllocation, Lowerable {
 
+    public static final NodeClass<BoxNode> TYPE = NodeClass.create(BoxNode.class);
     protected final Kind boxingKind;
 
     public BoxNode(ValueNode value, ResolvedJavaType resultType, Kind boxingKind) {
-        super(StampFactory.exactNonNull(resultType), value);
+        super(TYPE, StampFactory.exactNonNull(resultType), value);
         this.boxingKind = boxingKind;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -38,6 +39,7 @@
 @NodeInfo
 public final class BranchProbabilityNode extends FloatingNode implements Simplifiable, Lowerable {
 
+    public static final NodeClass<BranchProbabilityNode> TYPE = NodeClass.create(BranchProbabilityNode.class);
     public static final double LIKELY_PROBABILITY = 0.6;
     public static final double NOT_LIKELY_PROBABILITY = 1 - LIKELY_PROBABILITY;
 
@@ -54,7 +56,7 @@
     @Input ValueNode condition;
 
     public BranchProbabilityNode(ValueNode probability, ValueNode condition) {
-        super(condition.stamp());
+        super(TYPE, condition.stamp());
         this.probability = probability;
         this.condition = condition;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -36,11 +36,12 @@
 @NodeInfo
 public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<BytecodeExceptionNode> TYPE = NodeClass.create(BytecodeExceptionNode.class);
     protected final Class<? extends Throwable> exceptionClass;
     @Input NodeInputList<ValueNode> arguments;
 
     public BytecodeExceptionNode(MetaAccessProvider metaAccess, Class<? extends Throwable> exceptionClass, ValueNode... arguments) {
-        super(StampFactory.exactNonNull(metaAccess.lookupJavaType(exceptionClass)));
+        super(TYPE, StampFactory.exactNonNull(metaAccess.lookupJavaType(exceptionClass)));
         this.exceptionClass = exceptionClass;
         this.arguments = new NodeInputList<>(this, arguments);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -32,6 +33,7 @@
 @NodeInfo
 public final class ComputeAddressNode extends FloatingNode implements LIRLowerable {
 
+    public static final NodeClass<ComputeAddressNode> TYPE = NodeClass.create(ComputeAddressNode.class);
     @Input ValueNode object;
     @Input(InputType.Association) ValueNode location;
 
@@ -44,7 +46,7 @@
     }
 
     public ComputeAddressNode(ValueNode object, ValueNode location, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         this.object = object;
         this.location = location;
     }
@@ -52,6 +54,6 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
         Value addr = getLocation().generateAddress(gen, gen.getLIRGeneratorTool(), gen.operand(getObject()));
-        gen.setResult(this, addr);
+        gen.setResult(this, gen.getLIRGeneratorTool().asAllocatable(addr));
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,11 +36,12 @@
 @NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
 public final class ConstantLocationNode extends LocationNode {
 
+    public static final NodeClass<ConstantLocationNode> TYPE = NodeClass.create(ConstantLocationNode.class);
     protected final LocationIdentity locationIdentity;
     protected final long displacement;
 
     public ConstantLocationNode(LocationIdentity identity, long displacement) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.locationIdentity = identity;
         this.displacement = displacement;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
@@ -32,6 +33,7 @@
  */
 @NodeInfo
 public abstract class FixedAccessNode extends DeoptimizingFixedWithNextNode implements Access {
+    public static final NodeClass<FixedAccessNode> TYPE = NodeClass.create(FixedAccessNode.class);
 
     @OptionalInput(InputType.Guard) protected GuardingNode guard;
     @Input protected ValueNode object;
@@ -64,16 +66,17 @@
         this.nullCheck = check;
     }
 
-    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp) {
-        this(object, location, stamp, BarrierType.NONE);
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp) {
+        this(c, object, location, stamp, BarrierType.NONE);
     }
 
-    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        this(object, location, stamp, null, barrierType, false, null);
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
+        this(c, object, location, stamp, null, barrierType, false, null);
     }
 
-    public FixedAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
-        super(stamp, stateBefore);
+    protected FixedAccessNode(NodeClass<? extends FixedAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
+                    FrameState stateBefore) {
+        super(c, stamp, stateBefore);
         this.object = object;
         this.location = location;
         this.guard = guard;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,12 +23,14 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
 public final class FixedValueAnchorNode extends FixedWithNextNode implements LIRLowerable, ValueProxy {
+    public static final NodeClass<FixedValueAnchorNode> TYPE = NodeClass.create(FixedValueAnchorNode.class);
 
     @Input ValueNode object;
 
@@ -37,7 +39,7 @@
     }
 
     public FixedValueAnchorNode(ValueNode object) {
-        super(StampFactory.forNodeIntrinsic());
+        super(TYPE, StampFactory.forNodeIntrinsic());
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
@@ -32,17 +33,19 @@
  */
 @NodeInfo
 public abstract class FloatableAccessNode extends FixedAccessNode {
+    public static final NodeClass<FloatableAccessNode> TYPE = NodeClass.create(FloatableAccessNode.class);
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp) {
-        super(object, location, stamp);
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp) {
+        super(c, object, location, stamp);
     }
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(object, location, stamp, guard, barrierType, false, null);
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(c, object, location, stamp, guard, barrierType, false, null);
     }
 
-    public FloatableAccessNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
-        super(object, location, stamp, guard, barrierType, nullCheck, stateBefore);
+    protected FloatableAccessNode(NodeClass<? extends FloatableAccessNode> c, ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck,
+                    FrameState stateBefore) {
+        super(c, object, location, stamp, guard, barrierType, nullCheck, stateBefore);
     }
 
     public abstract FloatingAccessNode asFloatingNode(MemoryNode lastLocationAccess);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,11 +24,13 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
 public abstract class FloatingAccessNode extends FloatingGuardedNode implements Access, MemoryAccess {
+    public static final NodeClass<FloatingAccessNode> TYPE = NodeClass.create(FloatingAccessNode.class);
 
     @Input ValueNode object;
     @Input(InputType.Association) LocationNode location;
@@ -50,14 +52,14 @@
         return location.getLocationIdentity();
     }
 
-    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp) {
-        super(stamp);
+    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, ValueNode object, LocationNode location, Stamp stamp) {
+        super(c, stamp);
         this.object = object;
         this.location = location;
     }
 
-    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(stamp, guard);
+    protected FloatingAccessNode(NodeClass<? extends FloatingAccessNode> c, ValueNode object, LocationNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
+        super(c, stamp, guard);
         this.object = object;
         this.location = location;
         this.barrierType = barrierType;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,7 +35,8 @@
  * relative location. This node does not null check the object.
  */
 @NodeInfo
-public class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable {
+public final class FloatingReadNode extends FloatingAccessNode implements LIRLowerable, Canonicalizable {
+    public static final NodeClass<FloatingReadNode> TYPE = NodeClass.create(FloatingReadNode.class);
 
     @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
 
@@ -48,7 +49,7 @@
     }
 
     public FloatingReadNode(ValueNode object, LocationNode location, MemoryNode lastLocationAccess, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(object, location, stamp, guard, barrierType);
+        super(TYPE, object, location, stamp, guard, barrierType);
         this.lastLocationAccess = lastLocationAccess;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,6 +37,7 @@
  */
 @NodeInfo(nameTemplate = "ForeignCall#{p#descriptor/s}", allowedUsageTypes = {InputType.Memory})
 public class ForeignCallNode extends AbstractMemoryCheckpoint implements LIRLowerable, DeoptimizingNode.DeoptDuring, MemoryCheckpoint.Multi {
+    public static final NodeClass<ForeignCallNode> TYPE = NodeClass.create(ForeignCallNode.class);
 
     @Input protected NodeInputList<ValueNode> arguments;
     @OptionalInput(InputType.State) protected FrameState stateDuring;
@@ -46,7 +47,7 @@
     protected int bci = BytecodeFrame.UNKNOWN_BCI;
 
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) {
-        super(StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
+        super(TYPE, StampFactory.forKind(Kind.fromJavaClass(descriptor.getResultType())));
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
@@ -57,14 +58,21 @@
     }
 
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp, List<ValueNode> arguments) {
-        super(stamp);
+        super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this, arguments);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
     }
 
+    protected ForeignCallNode(NodeClass<? extends ForeignCallNode> c, ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
+        super(c, stamp);
+        this.arguments = new NodeInputList<>(this);
+        this.descriptor = descriptor;
+        this.foreignCalls = foreignCalls;
+    }
+
     public ForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         this.arguments = new NodeInputList<>(this);
         this.descriptor = descriptor;
         this.foreignCalls = foreignCalls;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,7 +38,8 @@
  * constants.
  */
 @NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}")
-public class IndexedLocationNode extends LocationNode implements Canonicalizable {
+public final class IndexedLocationNode extends LocationNode implements Canonicalizable {
+    public static final NodeClass<IndexedLocationNode> TYPE = NodeClass.create(IndexedLocationNode.class);
 
     protected final LocationIdentity locationIdentity;
     protected final long displacement;
@@ -64,7 +65,7 @@
     }
 
     public IndexedLocationNode(LocationIdentity identity, long displacement, ValueNode index, int indexScaling) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         assert index != null;
         assert indexScaling != 0;
         this.locationIdentity = identity;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -37,12 +38,13 @@
  * values. The actual implementation of the switch will be decided by the backend.
  */
 @NodeInfo
-public class IntegerSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
+public final class IntegerSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
+    public static final NodeClass<IntegerSwitchNode> TYPE = NodeClass.create(IntegerSwitchNode.class);
 
     protected final int[] keys;
 
     public IntegerSwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
-        super(value, successors, keySuccessors, keyProbabilities);
+        super(TYPE, value, successors, keySuccessors, keyProbabilities);
         assert keySuccessors.length == keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
         this.keys = keys;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Sat Feb 21 19:55:33 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
@@ -35,13 +35,14 @@
  * barriers, implicit conversions and optionally oop uncompression.
  */
 @NodeInfo
-public class JavaReadNode extends FixedAccessNode implements Lowerable, GuardingNode, Canonicalizable {
+public final class JavaReadNode extends FixedAccessNode implements Lowerable, GuardingNode, Canonicalizable {
 
+    public static final NodeClass<JavaReadNode> TYPE = NodeClass.create(JavaReadNode.class);
     protected final Kind readKind;
     protected final boolean compressible;
 
     public JavaReadNode(Kind readKind, ValueNode object, LocationNode location, BarrierType barrierType, boolean compressible) {
-        super(object, location, StampFactory.forKind(readKind), barrierType);
+        super(TYPE, object, location, StampFactory.forKind(readKind), barrierType);
         this.readKind = readKind;
         this.compressible = compressible;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Sat Feb 21 19:55:33 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
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -32,13 +33,14 @@
  * write barriers, implicit conversions and optionally oop compression.
  */
 @NodeInfo
-public class JavaWriteNode extends AbstractWriteNode implements Lowerable, StateSplit, MemoryAccess, MemoryCheckpoint.Single {
+public final class JavaWriteNode extends AbstractWriteNode implements Lowerable, StateSplit, MemoryAccess, MemoryCheckpoint.Single {
 
+    public static final NodeClass<JavaWriteNode> TYPE = NodeClass.create(JavaWriteNode.class);
     protected final Kind writeKind;
     protected final boolean compressible;
 
     public JavaWriteNode(Kind writeKind, ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean compressible, boolean initialization) {
-        super(object, value, location, barrierType, initialization);
+        super(TYPE, object, value, location, barrierType, initialization);
         this.writeKind = writeKind;
         this.compressible = compressible;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -35,6 +36,7 @@
 @NodeInfo
 public final class LoadHubNode extends FloatingGuardedNode implements Lowerable, Canonicalizable, Virtualizable {
 
+    public static final NodeClass<LoadHubNode> TYPE = NodeClass.create(LoadHubNode.class);
     @Input ValueNode value;
 
     public ValueNode getValue() {
@@ -51,7 +53,7 @@
     }
 
     public LoadHubNode(@InjectedNodeParameter StampProvider stampProvider, ValueNode value, ValueNode guard) {
-        super(hubStamp(stampProvider, value), (GuardingNode) guard);
+        super(TYPE, hubStamp(stampProvider, value), (GuardingNode) guard);
         assert value != guard;
         this.value = value;
     }
@@ -73,10 +75,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,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.*;
@@ -35,8 +36,9 @@
  * Loads a method from the virtual method table of a given hub.
  */
 @NodeInfo
-public class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
+public final class LoadMethodNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
 
+    public static final NodeClass<LoadMethodNode> TYPE = NodeClass.create(LoadMethodNode.class);
     @Input ValueNode hub;
     protected final ResolvedJavaMethod method;
     protected final ResolvedJavaType receiverType;
@@ -46,7 +48,7 @@
     }
 
     public LoadMethodNode(@InjectedNodeParameter Stamp stamp, ResolvedJavaMethod method, ResolvedJavaType receiverType, ValueNode hub) {
-        super(stamp);
+        super(TYPE, stamp);
         this.receiverType = receiverType;
         this.hub = hub;
         this.method = method;
@@ -68,10 +70,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/extended/LocationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -38,14 +39,16 @@
 @NodeInfo(allowedUsageTypes = {InputType.Association})
 public abstract class LocationNode extends FloatingNode implements LIRLowerable, ValueNumberable {
 
+    public static final NodeClass<LocationNode> TYPE = NodeClass.create(LocationNode.class);
+
     /**
      * Marker interface for locations in snippets.
      */
     public interface Location {
     }
 
-    protected LocationNode(Stamp stamp) {
-        super(stamp);
+    protected LocationNode(NodeClass<? extends LocationNode> c, Stamp stamp) {
+        super(c, stamp);
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -31,6 +31,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -39,12 +40,13 @@
  * Creates a memory barrier.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class MembarNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
+public final class MembarNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<MembarNode> TYPE = NodeClass.create(MembarNode.class);
     protected final int barriers;
 
     public MembarNode(int barriers) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.barriers = barriers;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Sat Feb 21 19:55:33 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
@@ -23,17 +23,19 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Guard})
-public class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode {
+public final class NullCheckNode extends DeoptimizingFixedWithNextNode implements LIRLowerable, GuardingNode {
 
+    public static final NodeClass<NullCheckNode> TYPE = NodeClass.create(NullCheckNode.class);
     @Input ValueNode object;
 
     public NullCheckNode(ValueNode object) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -28,10 +28,12 @@
 import com.oracle.graal.nodes.*;
 
 @NodeInfo(nameTemplate = "OSRLocal({p#index})")
-public class OSRLocalNode extends AbstractLocalNode implements IterableNodeType {
+public final class OSRLocalNode extends AbstractLocalNode implements IterableNodeType {
+
+    public static final NodeClass<OSRLocalNode> TYPE = NodeClass.create(OSRLocalNode.class);
 
     public OSRLocalNode(int index, Stamp stamp) {
-        super(index, stamp);
+        super(TYPE, index, stamp);
     }
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 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
@@ -22,14 +22,18 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class OSRStartNode extends StartNode implements Lowerable {
+public final class OSRStartNode extends StartNode implements Lowerable {
+    public static final NodeClass<OSRStartNode> TYPE = NodeClass.create(OSRStartNode.class);
+
     public OSRStartNode() {
+        super(TYPE);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -37,18 +37,20 @@
  * Reads an {@linkplain FixedAccessNode accessed} value.
  */
 @NodeInfo
-public class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode {
+public final class ReadNode extends FloatableAccessNode implements LIRLowerable, Canonicalizable, PiPushable, Virtualizable, GuardingNode {
+
+    public static final NodeClass<ReadNode> TYPE = NodeClass.create(ReadNode.class);
 
     public ReadNode(ValueNode object, ValueNode location, Stamp stamp, BarrierType barrierType) {
-        super(object, location, stamp, null, barrierType);
+        super(TYPE, object, location, stamp, null, barrierType);
     }
 
     public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType) {
-        super(object, location, stamp, guard, barrierType);
+        super(TYPE, object, location, stamp, guard, barrierType);
     }
 
     public ReadNode(ValueNode object, ValueNode location, Stamp stamp, GuardingNode guard, BarrierType barrierType, boolean nullCheck, FrameState stateBefore) {
-        super(object, location, stamp, guard, barrierType, nullCheck, stateBefore);
+        super(TYPE, object, location, stamp, guard, barrierType, nullCheck, stateBefore);
     }
 
     public ReadNode(ValueNode object, ValueNode location, ValueNode guard, BarrierType barrierType) {
@@ -57,7 +59,7 @@
          * location is a parameter, i.e., a ParameterNode, the constructor cannot use the declared
          * type LocationNode.
          */
-        super(object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
+        super(TYPE, object, location, StampFactory.forNodeIntrinsic(), (GuardingNode) guard, barrierType);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Sat Feb 21 19:55:33 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
@@ -23,13 +23,15 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class StoreHubNode extends FixedWithNextNode implements Lowerable {
+public final class StoreHubNode extends FixedWithNextNode implements Lowerable {
 
+    public static final NodeClass<StoreHubNode> TYPE = NodeClass.create(StoreHubNode.class);
     @Input ValueNode value;
     @Input ValueNode object;
 
@@ -42,7 +44,7 @@
     }
 
     public StoreHubNode(ValueNode object, ValueNode value) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.value = value;
         this.object = object;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -37,6 +37,7 @@
 @NodeInfo
 public abstract class SwitchNode extends ControlSplitNode {
 
+    public static final NodeClass<SwitchNode> TYPE = NodeClass.create(SwitchNode.class);
     @Successor protected NodeSuccessorList<AbstractBeginNode> successors;
     @Input protected ValueNode value;
 
@@ -50,8 +51,8 @@
      * @param value the instruction that provides the value to be switched over
      * @param successors the list of successors of this switch
      */
-    public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
-        super(StampFactory.forVoid());
+    protected SwitchNode(NodeClass<? extends SwitchNode> c, ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
+        super(c, StampFactory.forVoid());
         assert value.stamp().getStackKind().isNumericInteger() || value.stamp() instanceof AbstractPointerStamp : value.stamp() + " key not supported by SwitchNode";
         assert keySuccessors.length == keyProbabilities.length;
         this.successors = new NodeSuccessorList<>(this, successors);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -31,15 +32,24 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
+public final class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
 
+    public static final NodeClass<UnboxNode> TYPE = NodeClass.create(UnboxNode.class);
     protected final Kind boxingKind;
 
-    public UnboxNode(ValueNode value, Kind boxingKind) {
-        super(StampFactory.forKind(boxingKind.getStackKind()), value);
+    protected UnboxNode(ValueNode value, Kind boxingKind) {
+        super(TYPE, StampFactory.forKind(boxingKind.getStackKind()), value);
         this.boxingKind = boxingKind;
     }
 
+    public static ValueNode create(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode value, Kind boxingKind) {
+        ValueNode synonym = findSynonym(metaAccess, constantReflection, value, boxingKind);
+        if (synonym != null) {
+            return synonym;
+        }
+        return new UnboxNode(value, boxingKind);
+    }
+
     public Kind getBoxingKind() {
         return boxingKind;
     }
@@ -63,11 +73,19 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+        ValueNode synonym = findSynonym(tool.getMetaAccess(), tool.getConstantReflection(), forValue, boxingKind);
+        if (synonym != null) {
+            return synonym;
+        }
+        return this;
+    }
+
+    private static ValueNode findSynonym(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ValueNode forValue, Kind boxingKind) {
         if (forValue.isConstant()) {
             JavaConstant constant = forValue.asJavaConstant();
-            JavaConstant unboxed = tool.getConstantReflection().unboxPrimitive(constant);
+            JavaConstant unboxed = constantReflection.unboxPrimitive(constant);
             if (unboxed != null && unboxed.getKind() == boxingKind) {
-                return ConstantNode.forConstant(unboxed, tool.getMetaAccess());
+                return ConstantNode.forConstant(unboxed, metaAccess);
             }
         } else if (forValue instanceof BoxNode) {
             BoxNode box = (BoxNode) forValue;
@@ -75,7 +93,7 @@
                 return box.getValue();
             }
         }
-        return this;
+        return null;
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,13 +33,14 @@
 @NodeInfo
 public abstract class UnsafeAccessNode extends FixedWithNextNode implements Canonicalizable {
 
+    public static final NodeClass<UnsafeAccessNode> TYPE = NodeClass.create(UnsafeAccessNode.class);
     @Input ValueNode object;
     @Input ValueNode offset;
     protected final Kind accessKind;
     protected final LocationIdentity locationIdentity;
 
-    public UnsafeAccessNode(Stamp stamp, ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity) {
-        super(stamp);
+    protected UnsafeAccessNode(NodeClass<? extends UnsafeAccessNode> c, Stamp stamp, ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity) {
+        super(c, stamp);
         assert accessKind != null;
         this.object = object;
         this.offset = offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -38,17 +38,18 @@
  * than the type this nodes casts to.
  */
 @NodeInfo
-public class UnsafeCastNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, GuardingNode, IterableNodeType, Canonicalizable, ValueProxy {
+public final class UnsafeCastNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, GuardingNode, IterableNodeType, Canonicalizable, ValueProxy {
 
+    public static final NodeClass<UnsafeCastNode> TYPE = NodeClass.create(UnsafeCastNode.class);
     @Input ValueNode object;
 
     public UnsafeCastNode(ValueNode object, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         this.object = object;
     }
 
     public UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) {
-        super(stamp, (GuardingNode) anchor);
+        super(TYPE, stamp, (GuardingNode) anchor);
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -36,7 +37,8 @@
  * performed before the load.
  */
 @NodeInfo
-public class UnsafeLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable {
+public final class UnsafeLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable {
+    public static final NodeClass<UnsafeLoadNode> TYPE = NodeClass.create(UnsafeLoadNode.class);
     @OptionalInput(InputType.Condition) LogicNode guardingCondition;
 
     public UnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity) {
@@ -44,7 +46,7 @@
     }
 
     public UnsafeLoadNode(ValueNode object, ValueNode offset, Kind accessKind, LocationIdentity locationIdentity, LogicNode condition) {
-        super(StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity);
+        super(TYPE, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity);
         this.guardingCondition = condition;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -36,8 +37,9 @@
  * performed before the store.
  */
 @NodeInfo
-public class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, MemoryCheckpoint.Single {
+public final class UnsafeStoreNode extends UnsafeAccessNode implements StateSplit, Lowerable, Virtualizable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<UnsafeStoreNode> TYPE = NodeClass.create(UnsafeStoreNode.class);
     @Input ValueNode value;
     @OptionalInput(InputType.State) FrameState stateAfter;
 
@@ -46,7 +48,7 @@
     }
 
     public UnsafeStoreNode(ValueNode object, ValueNode offset, ValueNode value, Kind accessKind, LocationIdentity locationIdentity, FrameState stateAfter) {
-        super(StampFactory.forVoid(), object, offset, accessKind, locationIdentity);
+        super(TYPE, StampFactory.forVoid(), object, offset, accessKind, locationIdentity);
         this.value = value;
         this.stateAfter = stateAfter;
         assert accessKind != Kind.Void && accessKind != Kind.Illegal;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 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.*;
@@ -34,12 +35,13 @@
  * The ValueAnchor instruction keeps non-CFG (floating) nodes above a certain point in the graph.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Anchor, InputType.Guard})
-public class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, AnchoringNode, GuardingNode {
+public final class ValueAnchorNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Virtualizable, AnchoringNode, GuardingNode {
 
+    public static final NodeClass<ValueAnchorNode> TYPE = NodeClass.create(ValueAnchorNode.class);
     @OptionalInput(InputType.Guard) ValueNode anchored;
 
     public ValueAnchorNode(ValueNode value) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.anchored = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -34,18 +35,20 @@
  * Writes a given {@linkplain #value() value} a {@linkplain FixedAccessNode memory location}.
  */
 @NodeInfo
-public class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable {
+public final class WriteNode extends AbstractWriteNode implements LIRLowerable, Simplifiable, Virtualizable {
+
+    public static final NodeClass<WriteNode> TYPE = NodeClass.create(WriteNode.class);
 
     public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType) {
-        super(object, value, location, barrierType);
+        super(TYPE, object, value, location, barrierType);
     }
 
     public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, boolean initialization) {
-        super(object, value, location, barrierType, initialization);
+        super(TYPE, object, value, location, barrierType, initialization);
     }
 
     public WriteNode(ValueNode object, ValueNode value, ValueNode location, BarrierType barrierType, GuardingNode guard, boolean initialization) {
-        super(object, value, location, barrierType, guard, initialization);
+        super(TYPE, object, value, location, barrierType, guard, initialization);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 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.*;
@@ -34,6 +35,7 @@
 @NodeInfo
 public abstract class AbstractNewArrayNode extends AbstractNewObjectNode implements ArrayLengthProvider {
 
+    public static final NodeClass<AbstractNewArrayNode> TYPE = NodeClass.create(AbstractNewArrayNode.class);
     @Input protected ValueNode length;
 
     @Override
@@ -41,8 +43,8 @@
         return length;
     }
 
-    public AbstractNewArrayNode(Stamp stamp, ValueNode length, boolean fillContents) {
-        super(stamp, fillContents);
+    public AbstractNewArrayNode(NodeClass<? extends AbstractNewArrayNode> c, Stamp stamp, ValueNode length, boolean fillContents) {
+        super(c, stamp, fillContents);
         this.length = length;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,10 +38,11 @@
 @NodeInfo
 public abstract class AbstractNewObjectNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable {
 
+    public static final NodeClass<AbstractNewObjectNode> TYPE = NodeClass.create(AbstractNewObjectNode.class);
     protected final boolean fillContents;
 
-    public AbstractNewObjectNode(Stamp stamp, boolean fillContents) {
-        super(stamp);
+    public AbstractNewObjectNode(NodeClass<? extends AbstractNewObjectNode> c, Stamp stamp, boolean fillContents) {
+        super(c, stamp);
         this.fillContents = fillContents;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
@@ -32,6 +33,7 @@
 @NodeInfo
 public abstract class AccessArrayNode extends FixedWithNextNode {
 
+    public static final NodeClass<AccessArrayNode> TYPE = NodeClass.create(AccessArrayNode.class);
     @Input protected ValueNode array;
 
     public ValueNode array() {
@@ -43,8 +45,8 @@
      *
      * @param array the instruction that produces the array object value
      */
-    public AccessArrayNode(Stamp stamp, ValueNode array) {
-        super(stamp);
+    public AccessArrayNode(NodeClass<? extends AccessArrayNode> c, Stamp stamp, ValueNode array) {
+        super(c, stamp);
         this.array = array;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -34,6 +35,7 @@
 @NodeInfo
 public abstract class AccessFieldNode extends FixedWithNextNode implements Lowerable {
 
+    public static final NodeClass<AccessFieldNode> TYPE = NodeClass.create(AccessFieldNode.class);
     @OptionalInput ValueNode object;
 
     protected final ResolvedJavaField field;
@@ -48,8 +50,8 @@
      * @param object the instruction producing the receiver object
      * @param field the compiler interface representation of the field
      */
-    public AccessFieldNode(Stamp stamp, ValueNode object, ResolvedJavaField field) {
-        super(stamp);
+    public AccessFieldNode(NodeClass<? extends AccessFieldNode> c, Stamp stamp, ValueNode object, ResolvedJavaField field) {
+        super(c, stamp);
         this.object = object;
         this.field = field;
         assert field.getDeclaringClass().isInitialized();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -35,6 +36,7 @@
 @NodeInfo
 public abstract class AccessIndexedNode extends AccessArrayNode implements Lowerable {
 
+    public static final NodeClass<AccessIndexedNode> TYPE = NodeClass.create(AccessIndexedNode.class);
     @Input protected ValueNode index;
     protected final Kind elementKind;
 
@@ -50,8 +52,8 @@
      * @param index the instruction producing the index
      * @param elementKind the kind of the elements of the array
      */
-    protected AccessIndexedNode(Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) {
-        super(stamp, array);
+    protected AccessIndexedNode(NodeClass<? extends AccessIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) {
+        super(c, stamp, array);
         this.index = index;
         this.elementKind = elementKind;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -37,6 +38,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public abstract class AccessMonitorNode extends AbstractMemoryCheckpoint implements MemoryCheckpoint, DeoptimizingNode.DeoptBefore, DeoptimizingNode.DeoptAfter {
 
+    public static final NodeClass<AccessMonitorNode> TYPE = NodeClass.create(AccessMonitorNode.class);
     @OptionalInput(InputType.State) FrameState stateBefore;
     @Input ValueNode object;
     @Input(InputType.Association) MonitorIdNode monitorId;
@@ -69,8 +71,8 @@
      *
      * @param object the instruction producing the object
      */
-    public AccessMonitorNode(ValueNode object, MonitorIdNode monitorId) {
-        super(StampFactory.forVoid());
+    protected AccessMonitorNode(NodeClass<? extends AccessMonitorNode> c, ValueNode object, MonitorIdNode monitorId) {
+        super(c, StampFactory.forVoid());
         this.object = object;
         this.monitorId = monitorId;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -36,6 +37,7 @@
 @NodeInfo
 public final class ArrayLengthNode extends FixedWithNextNode implements Canonicalizable.Unary<ValueNode>, Lowerable, Virtualizable {
 
+    public static final NodeClass<ArrayLengthNode> TYPE = NodeClass.create(ArrayLengthNode.class);
     @Input ValueNode array;
 
     public ValueNode array() {
@@ -47,11 +49,16 @@
     }
 
     public ArrayLengthNode(ValueNode array) {
-        super(StampFactory.positiveInt());
+        super(TYPE, StampFactory.positiveInt());
         this.array = array;
     }
 
     public static ValueNode create(ValueNode forValue, ConstantReflectionProvider constantReflection) {
+        if (forValue instanceof NewArrayNode) {
+            NewArrayNode newArray = (NewArrayNode) forValue;
+            return newArray.length();
+        }
+
         ValueNode length = readArrayLengthConstant(forValue, constantReflection);
         if (length != null) {
             return length;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -38,6 +39,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<AtomicReadAndAddNode> TYPE = NodeClass.create(AtomicReadAndAddNode.class);
     @Input ValueNode object;
     @Input ValueNode offset;
     @Input ValueNode delta;
@@ -45,7 +47,7 @@
     protected final LocationIdentity locationIdentity;
 
     public AtomicReadAndAddNode(ValueNode object, ValueNode offset, ValueNode delta, LocationIdentity locationIdentity) {
-        super(StampFactory.forKind(delta.getKind()));
+        super(TYPE, StampFactory.forKind(delta.getKind()));
         this.object = object;
         this.offset = offset;
         this.delta = delta;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -39,6 +40,7 @@
 @NodeInfo
 public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<AtomicReadAndWriteNode> TYPE = NodeClass.create(AtomicReadAndWriteNode.class);
     @Input ValueNode object;
     @Input ValueNode offset;
     @Input ValueNode newValue;
@@ -47,7 +49,7 @@
     protected final LocationIdentity locationIdentity;
 
     public AtomicReadAndWriteNode(ValueNode object, ValueNode offset, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
-        super(StampFactory.forKind(newValue.getKind()));
+        super(TYPE, StampFactory.forKind(newValue.getKind()));
         this.object = object;
         this.offset = offset;
         this.newValue = newValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -36,6 +37,7 @@
 @NodeInfo
 public final class CheckCastDynamicNode extends FixedWithNextNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
 
+    public static final NodeClass<CheckCastDynamicNode> TYPE = NodeClass.create(CheckCastDynamicNode.class);
     @Input ValueNode object;
     @Input ValueNode hub;
 
@@ -46,7 +48,7 @@
     protected final boolean forStoreCheck;
 
     public CheckCastDynamicNode(ValueNode hub, ValueNode object, boolean forStoreCheck) {
-        super(object.stamp());
+        super(TYPE, object.stamp());
         this.hub = hub;
         this.object = object;
         this.forStoreCheck = forStoreCheck;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Sat Feb 21 19:55:33 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.*;
@@ -43,6 +44,7 @@
 @NodeInfo
 public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, Simplifiable, Lowerable, Virtualizable, ValueProxy {
 
+    public static final NodeClass<CheckCastNode> TYPE = NodeClass.create(CheckCastNode.class);
     @Input protected ValueNode object;
     protected final ResolvedJavaType type;
     protected final JavaTypeProfile profile;
@@ -54,7 +56,7 @@
     protected final boolean forStoreCheck;
 
     public CheckCastNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck) {
-        super(StampFactory.declaredTrusted(type));
+        super(TYPE, StampFactory.declaredTrusted(type));
         assert type != null;
         this.type = type;
         this.object = object;
@@ -62,6 +64,22 @@
         this.forStoreCheck = forStoreCheck;
     }
 
+    public static ValueNode create(ResolvedJavaType inputType, ValueNode object, JavaTypeProfile profile, boolean forStoreCheck, Assumptions assumptions) {
+        ResolvedJavaType type = inputType;
+        ValueNode synonym = findSynonym(type, object);
+        if (synonym != null) {
+            return synonym;
+        }
+        if (assumptions != null) {
+            ResolvedJavaType uniqueConcreteType = type.findUniqueConcreteSubtype();
+            if (uniqueConcreteType != null && !uniqueConcreteType.equals(type)) {
+                assumptions.recordConcreteSubtype(type, uniqueConcreteType);
+                type = uniqueConcreteType;
+            }
+        }
+        return new CheckCastNode(type, object, profile, forStoreCheck);
+    }
+
     public boolean isForStoreCheck() {
         return forStoreCheck;
     }
@@ -144,22 +162,17 @@
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ResolvedJavaType objectType = StampTool.typeOrNull(object());
-        if (objectType != null && type.isAssignableFrom(objectType)) {
-            // we don't have to check for null types here because they will also pass the
-            // checkcast.
-            return object();
+        ValueNode synonym = findSynonym(type, object());
+        if (synonym != null) {
+            return synonym;
         }
 
-        if (StampTool.isPointerAlwaysNull(object())) {
-            return object();
-        }
-
-        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);
             }
         }
@@ -167,6 +180,20 @@
         return this;
     }
 
+    private static ValueNode findSynonym(ResolvedJavaType type, ValueNode object) {
+        ResolvedJavaType objectType = StampTool.typeOrNull(object);
+        if (objectType != null && type.isAssignableFrom(objectType)) {
+            // we don't have to check for null types here because they will also pass the
+            // checkcast.
+            return object;
+        }
+
+        if (StampTool.isPointerAlwaysNull(object)) {
+            return object;
+        }
+        return null;
+    }
+
     @Override
     public void simplify(SimplifierTool tool) {
         // if the previous node is also a checkcast, with a less precise and compatible type,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ClassIsAssignableFromNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.java;
+
+import com.oracle.graal.api.meta.*;
+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.spi.*;
+
+/**
+ * The {@code ClassIsAssignableFromNode} represents a type check against {@link Class} instead of
+ * against instances. This is used, for instance, to intrinsify
+ * {@link Class#isAssignableFrom(Class)} .
+ */
+@NodeInfo
+public final class ClassIsAssignableFromNode extends LogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
+
+    public static final NodeClass<ClassIsAssignableFromNode> TYPE = NodeClass.create(ClassIsAssignableFromNode.class);
+    @Input ValueNode thisClass;
+    @Input ValueNode otherClass;
+
+    public ClassIsAssignableFromNode(ValueNode thisClass, ValueNode otherClass) {
+        super(TYPE);
+        this.thisClass = thisClass;
+        this.otherClass = otherClass;
+    }
+
+    public Object getThisClass() {
+        return thisClass;
+    }
+
+    public Object getOtherClass() {
+        return otherClass;
+    }
+
+    @Override
+    public ValueNode getX() {
+        return thisClass;
+    }
+
+    @Override
+    public ValueNode getY() {
+        return otherClass;
+    }
+
+    @Override
+    public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
+        if (forX.isConstant() && forY.isConstant()) {
+            ConstantReflectionProvider constantReflection = tool.getConstantReflection();
+            ResolvedJavaType thisType = constantReflection.asJavaType(forX.asJavaConstant());
+            ResolvedJavaType otherType = constantReflection.asJavaType(forY.asJavaConstant());
+            if (thisType != null && otherType != null) {
+                return LogicConstantNode.forBoolean(thisType.isAssignableFrom(otherType));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        tool.getLowerer().lower(this, tool);
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -38,6 +39,7 @@
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class CompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<CompareAndSwapNode> TYPE = NodeClass.create(CompareAndSwapNode.class);
     @Input ValueNode object;
     @Input ValueNode offset;
     @Input ValueNode expected;
@@ -47,7 +49,7 @@
     protected final LocationIdentity locationIdentity;
 
     public CompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, Kind valueKind, LocationIdentity locationIdentity) {
-        super(StampFactory.forKind(Kind.Boolean.getStackKind()));
+        super(TYPE, StampFactory.forKind(Kind.Boolean.getStackKind()));
         assert expected.stamp().isCompatible(newValue.stamp());
         this.object = object;
         this.offset = offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
  */
 @NodeInfo
 public class DynamicNewArrayNode extends AbstractNewArrayNode {
+    public static final NodeClass<DynamicNewArrayNode> TYPE = NodeClass.create(DynamicNewArrayNode.class);
 
     @Input ValueNode elementType;
 
@@ -49,11 +50,15 @@
     protected final Kind knownElementKind;
 
     public DynamicNewArrayNode(ValueNode elementType, ValueNode length) {
-        this(elementType, length, true, null);
+        this(TYPE, elementType, length, true, null);
     }
 
     public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind) {
-        super(StampFactory.objectNonNull(), length, fillContents);
+        this(TYPE, elementType, length, fillContents, knownElementKind);
+    }
+
+    protected DynamicNewArrayNode(NodeClass<? extends DynamicNewArrayNode> c, ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind) {
+        super(c, StampFactory.objectNonNull(), length, fillContents);
         this.elementType = elementType;
         this.knownElementKind = knownElementKind;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,11 +31,12 @@
 
 @NodeInfo
 public final class DynamicNewInstanceNode extends AbstractNewObjectNode implements Canonicalizable {
+    public static final NodeClass<DynamicNewInstanceNode> TYPE = NodeClass.create(DynamicNewInstanceNode.class);
 
     @Input ValueNode clazz;
 
     public DynamicNewInstanceNode(ValueNode clazz, boolean fillContents) {
-        super(StampFactory.objectNonNull(), fillContents);
+        super(TYPE, StampFactory.objectNonNull(), fillContents);
         this.clazz = clazz;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -35,9 +36,10 @@
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
 public final class ExceptionObjectNode extends DispatchBeginNode implements Lowerable, MemoryCheckpoint.Single {
+    public static final NodeClass<ExceptionObjectNode> TYPE = NodeClass.create(ExceptionObjectNode.class);
 
     public ExceptionObjectNode(MetaAccessProvider metaAccess) {
-        super(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class)));
+        super(TYPE, StampFactory.declaredNonNull(metaAccess.lookupJavaType(Throwable.class)));
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -36,11 +37,13 @@
  */
 @NodeInfo
 public class InstanceOfDynamicNode extends LogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
+    public static final NodeClass<InstanceOfDynamicNode> TYPE = NodeClass.create(InstanceOfDynamicNode.class);
 
     @Input ValueNode object;
     @Input ValueNode mirror;
 
     public InstanceOfDynamicNode(ValueNode mirror, ValueNode object) {
+        super(TYPE);
         this.mirror = mirror;
         this.object = object;
         assert mirror.getKind() == Kind.Object : mirror.getKind();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,8 +22,10 @@
  */
 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.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -34,18 +36,29 @@
  * The {@code InstanceOfNode} represents an instanceof test.
  */
 @NodeInfo
-public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
+public final class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
+    public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);
 
     protected final ResolvedJavaType type;
     protected JavaTypeProfile profile;
 
     public InstanceOfNode(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
-        super(object);
+        super(TYPE, object);
         this.type = type;
         this.profile = profile;
         assert type != null;
     }
 
+    public static LogicNode create(ResolvedJavaType type, ValueNode object, JavaTypeProfile profile) {
+        ObjectStamp objectStamp = (ObjectStamp) object.stamp();
+        LogicNode constantValue = findSynonym(type, objectStamp.type(), objectStamp.nonNull(), objectStamp.isExactType());
+        if (constantValue != null) {
+            return constantValue;
+        } else {
+            return new InstanceOfNode(type, object, profile);
+        }
+    }
+
     @Override
     public void lower(LoweringTool tool) {
         tool.getLowerer().lower(this, tool);
@@ -67,12 +80,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;
                     }
                 }
@@ -82,7 +96,25 @@
     }
 
     private ValueNode checkInstanceOf(ValueNode forValue, ResolvedJavaType inputType, boolean nonNull, boolean exactType) {
-        boolean subType = type().isAssignableFrom(inputType);
+        ValueNode result = findSynonym(type(), inputType, nonNull, exactType);
+        if (result != null) {
+            return result;
+        }
+        if (type().isAssignableFrom(inputType)) {
+            if (!nonNull) {
+                // the instanceof matches if the object is non-null, so return true
+                // depending on the null-ness.
+                return LogicNegationNode.create(new IsNullNode(forValue));
+            }
+        }
+        return null;
+    }
+
+    public static LogicNode findSynonym(ResolvedJavaType type, ResolvedJavaType inputType, boolean nonNull, boolean exactType) {
+        if (inputType == null) {
+            return null;
+        }
+        boolean subType = type.isAssignableFrom(inputType);
         if (subType) {
             if (nonNull) {
                 // the instanceOf matches, so return true
@@ -95,21 +127,14 @@
                 // also make the check fail.
                 return LogicConstantNode.contradiction();
             } else {
-                boolean superType = inputType.isAssignableFrom(type());
-                if (!superType && !inputType.isInterface() && !type().isInterface()) {
+                boolean superType = inputType.isAssignableFrom(type);
+                if (!superType && !inputType.isInterface() && !type.isInterface()) {
                     return LogicConstantNode.contradiction();
                 }
                 // since the subtype comparison was only performed on a declared type we don't
                 // really know if it might be true at run time...
             }
         }
-        if (type().isAssignableFrom(inputType)) {
-            if (!nonNull) {
-                // the instanceof matches if the object is non-null, so return true
-                // depending on the null-ness.
-                return new LogicNegationNode(new IsNullNode(forValue));
-            }
-        }
         return null;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,15 +23,18 @@
 package com.oracle.graal.nodes.java;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
+public final class LoadExceptionObjectNode extends AbstractStateSplit implements Lowerable {
+
+    public static final NodeClass<LoadExceptionObjectNode> TYPE = NodeClass.create(LoadExceptionObjectNode.class);
 
     public LoadExceptionObjectNode(Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -39,8 +40,10 @@
 @NodeInfo(nameTemplate = "LoadField#{p#field/s}")
 public final class LoadFieldNode extends AccessFieldNode implements Canonicalizable.Unary<ValueNode>, VirtualizableRoot, UncheckedInterfaceProvider {
 
+    public static final NodeClass<LoadFieldNode> TYPE = NodeClass.create(LoadFieldNode.class);
+
     public LoadFieldNode(ValueNode object, ResolvedJavaField field) {
-        super(createStamp(field), object, field);
+        super(TYPE, createStamp(field), object, field);
     }
 
     public ValueNode getValue() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -37,6 +37,8 @@
 @NodeInfo
 public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable, Canonicalizable {
 
+    public static final NodeClass<LoadIndexedNode> TYPE = NodeClass.create(LoadIndexedNode.class);
+
     /**
      * Creates a new LoadIndexedNode.
      *
@@ -45,7 +47,7 @@
      * @param elementKind the element type
      */
     public LoadIndexedNode(ValueNode array, ValueNode index, Kind elementKind) {
-        this(createStamp(array, elementKind), array, index, elementKind);
+        this(TYPE, createStamp(array, elementKind), array, index, elementKind);
     }
 
     public static ValueNode create(ValueNode array, ValueNode index, Kind elementKind, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
@@ -56,8 +58,8 @@
         return new LoadIndexedNode(array, index, elementKind);
     }
 
-    protected LoadIndexedNode(Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) {
-        super(stamp, array, index, elementKind);
+    protected LoadIndexedNode(NodeClass<? extends LoadIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, Kind elementKind) {
+        super(c, stamp, array, index, elementKind);
     }
 
     private static Stamp createStamp(ValueNode array, Kind kind) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Sat Feb 21 19:55:33 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
@@ -25,6 +25,7 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -35,13 +36,14 @@
  * {@link Unsafe#getAndSetInt(Object, long, int)} .
  */
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class LoweredAtomicReadAndWriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
+public final class LoweredAtomicReadAndWriteNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<LoweredAtomicReadAndWriteNode> TYPE = NodeClass.create(LoweredAtomicReadAndWriteNode.class);
     @Input ValueNode newValue;
     @OptionalInput(InputType.State) FrameState stateAfter;
 
     public LoweredAtomicReadAndWriteNode(ValueNode object, LocationNode location, ValueNode newValue, BarrierType barrierType) {
-        super(object, location, newValue.stamp().unrestricted(), barrierType);
+        super(TYPE, object, location, newValue.stamp().unrestricted(), barrierType);
         this.newValue = newValue;
     }
 
@@ -73,7 +75,7 @@
         return false;
     }
 
-    public final ValueNode getNewValue() {
+    public ValueNode getNewValue() {
         return newValue;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -33,8 +34,9 @@
  * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}.
  */
 @NodeInfo(allowedUsageTypes = {InputType.Value, InputType.Memory})
-public class LoweredCompareAndSwapNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
+public final class LoweredCompareAndSwapNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single {
 
+    public static final NodeClass<LoweredCompareAndSwapNode> TYPE = NodeClass.create(LoweredCompareAndSwapNode.class);
     @Input ValueNode expectedValue;
     @Input ValueNode newValue;
     @OptionalInput(InputType.State) FrameState stateAfter;
@@ -62,7 +64,7 @@
     }
 
     public LoweredCompareAndSwapNode(ValueNode object, LocationNode location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) {
-        super(object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType);
+        super(TYPE, object, location, StampFactory.forKind(Kind.Boolean.getStackKind()), barrierType);
         assert expectedValue.getKind() == newValue.getKind();
         this.expectedValue = expectedValue;
         this.newValue = newValue;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -34,10 +34,15 @@
 
 @NodeInfo
 public class MethodCallTargetNode extends CallTargetNode implements IterableNodeType, Simplifiable {
+    public static final NodeClass<MethodCallTargetNode> TYPE = NodeClass.create(MethodCallTargetNode.class);
     protected final JavaType returnType;
 
     public MethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType) {
-        super(arguments, targetMethod, invokeKind);
+        this(TYPE, invokeKind, targetMethod, arguments, returnType);
+    }
+
+    protected MethodCallTargetNode(NodeClass<? extends MethodCallTargetNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType) {
+        super(c, arguments, targetMethod, invokeKind);
         this.returnType = returnType;
     }
 
@@ -94,7 +99,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 +124,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 +150,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);
@@ -242,7 +248,7 @@
     }
 
     public static MethodCallTargetNode find(StructuredGraph graph, ResolvedJavaMethod method) {
-        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.TYPE)) {
             if (target.targetMethod().equals(method)) {
                 return target;
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,8 +35,10 @@
 @NodeInfo
 public final class MonitorEnterNode extends AccessMonitorNode implements Virtualizable, Lowerable, IterableNodeType, MonitorEnter, MemoryCheckpoint.Single {
 
+    public static final NodeClass<MonitorEnterNode> TYPE = NodeClass.create(MonitorEnterNode.class);
+
     public MonitorEnterNode(ValueNode object, MonitorIdNode monitorId) {
-        super(object, monitorId);
+        super(TYPE, object, monitorId);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -39,10 +39,11 @@
 @NodeInfo
 public final class MonitorExitNode extends AccessMonitorNode implements Virtualizable, Simplifiable, Lowerable, IterableNodeType, MonitorExit, MemoryCheckpoint.Single {
 
+    public static final NodeClass<MonitorExitNode> TYPE = NodeClass.create(MonitorExitNode.class);
     @OptionalInput ValueNode escapedReturnValue;
 
     public MonitorExitNode(ValueNode object, MonitorIdNode monitorId, ValueNode escapedReturnValue) {
-        super(object, monitorId);
+        super(TYPE, object, monitorId);
         this.escapedReturnValue = escapedReturnValue;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Sat Feb 21 19:55:33 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
@@ -36,10 +36,15 @@
 @NodeInfo(allowedUsageTypes = {InputType.Association})
 public class MonitorIdNode extends ValueNode implements IterableNodeType, LIRLowerable {
 
+    public static final NodeClass<MonitorIdNode> TYPE = NodeClass.create(MonitorIdNode.class);
     protected int lockDepth;
 
     public MonitorIdNode(int lockDepth) {
-        super(StampFactory.forVoid());
+        this(TYPE, lockDepth);
+    }
+
+    protected MonitorIdNode(NodeClass<? extends MonitorIdNode> c, int lockDepth) {
+        super(c, StampFactory.forVoid());
         this.lockDepth = lockDepth;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -40,8 +41,14 @@
 @NodeInfo
 public class NewArrayNode extends AbstractNewArrayNode implements VirtualizableAllocation {
 
+    public static final NodeClass<NewArrayNode> TYPE = NodeClass.create(NewArrayNode.class);
+
     public NewArrayNode(ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
-        super(StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
+        super(TYPE, StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
+    }
+
+    protected NewArrayNode(NodeClass<? extends NewArrayNode> c, ResolvedJavaType elementType, ValueNode length, boolean fillContents) {
+        super(c, StampFactory.exactNonNull(elementType.getArrayClass()), length, fillContents);
     }
 
     @NodeIntrinsic
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -38,10 +39,11 @@
 @NodeInfo(nameTemplate = "New {p#instanceClass/s}")
 public final class NewInstanceNode extends AbstractNewObjectNode implements VirtualizableAllocation {
 
+    public static final NodeClass<NewInstanceNode> TYPE = NodeClass.create(NewInstanceNode.class);
     protected final ResolvedJavaType instanceClass;
 
     public NewInstanceNode(ResolvedJavaType type, boolean fillContents) {
-        super(StampFactory.exactNonNull(type), fillContents);
+        super(TYPE, StampFactory.exactNonNull(type), fillContents);
         assert !type.isArray() && !type.isInterface() && !type.isPrimitive();
         this.instanceClass = type;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
 @NodeInfo
 public final class NewMultiArrayNode extends DeoptimizingFixedWithNextNode implements Lowerable, ArrayLengthProvider {
 
+    public static final NodeClass<NewMultiArrayNode> TYPE = NodeClass.create(NewMultiArrayNode.class);
     @Input protected NodeInputList<ValueNode> dimensions;
     protected final ResolvedJavaType type;
 
@@ -51,7 +52,7 @@
     }
 
     public NewMultiArrayNode(ResolvedJavaType type, ValueNode[] dimensions) {
-        super(StampFactory.exactNonNull(type));
+        super(TYPE, StampFactory.exactNonNull(type));
         this.type = type;
         this.dimensions = new NodeInputList<>(this, dimensions);
         assert dimensions.length > 0 && type.isArray();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,7 @@
 
 import com.oracle.graal.api.code.*;
 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.*;
@@ -36,13 +37,14 @@
  * constructor.
  */
 @NodeInfo
-public class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable.Unary<ValueNode>, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
+public final class RegisterFinalizerNode extends AbstractStateSplit implements Canonicalizable.Unary<ValueNode>, LIRLowerable, Virtualizable, DeoptimizingNode.DeoptAfter {
 
+    public static final NodeClass<RegisterFinalizerNode> TYPE = NodeClass.create(RegisterFinalizerNode.class);
     @OptionalInput(InputType.State) FrameState deoptState;
     @Input ValueNode value;
 
     public RegisterFinalizerNode(ValueNode value) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.value = value;
     }
 
@@ -67,7 +69,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 +82,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/java/SelfReplacingMethodCallTargetNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Sat Feb 21 19:55:33 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
@@ -37,8 +37,9 @@
  * inlined.
  */
 @NodeInfo
-public class SelfReplacingMethodCallTargetNode extends MethodCallTargetNode implements Lowerable {
+public final class SelfReplacingMethodCallTargetNode extends MethodCallTargetNode implements Lowerable {
 
+    public static final NodeClass<SelfReplacingMethodCallTargetNode> TYPE = NodeClass.create(SelfReplacingMethodCallTargetNode.class);
     // Replacement method data
     protected final ResolvedJavaMethod replacementTargetMethod;
     protected final JavaType replacementReturnType;
@@ -46,7 +47,7 @@
 
     public SelfReplacingMethodCallTargetNode(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] arguments, JavaType returnType, ResolvedJavaMethod replacementTargetMethod,
                     ValueNode[] replacementArguments, JavaType replacementReturnType) {
-        super(invokeKind, targetMethod, arguments, returnType);
+        super(TYPE, invokeKind, targetMethod, arguments, returnType);
         this.replacementTargetMethod = replacementTargetMethod;
         this.replacementReturnType = replacementReturnType;
         this.replacementArguments = new NodeInputList<>(this, replacementArguments);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,7 +34,8 @@
  * The {@code StoreFieldNode} represents a write to a static or instance field.
  */
 @NodeInfo(nameTemplate = "StoreField#{p#field/s}")
-public class StoreFieldNode extends AccessFieldNode implements StateSplit, VirtualizableRoot {
+public final class StoreFieldNode extends AccessFieldNode implements StateSplit, VirtualizableRoot {
+    public static final NodeClass<StoreFieldNode> TYPE = NodeClass.create(StoreFieldNode.class);
 
     @Input ValueNode value;
     @OptionalInput(InputType.State) FrameState stateAfter;
@@ -57,12 +59,12 @@
     }
 
     public StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value) {
-        super(StampFactory.forVoid(), object, field);
+        super(TYPE, StampFactory.forVoid(), object, field);
         this.value = value;
     }
 
     public StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value, FrameState stateAfter) {
-        super(StampFactory.forVoid(), object, field);
+        super(TYPE, StampFactory.forVoid(), object, field);
         this.value = value;
         this.stateAfter = stateAfter;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,8 +34,9 @@
  * The {@code StoreIndexedNode} represents a write to an array element.
  */
 @NodeInfo
-public class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable, Virtualizable {
+public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable, Virtualizable {
 
+    public static final NodeClass<StoreIndexedNode> TYPE = NodeClass.create(StoreIndexedNode.class);
     @Input ValueNode value;
     @OptionalInput(InputType.State) FrameState stateAfter;
 
@@ -57,7 +59,7 @@
     }
 
     public StoreIndexedNode(ValueNode array, ValueNode index, Kind elementKind, ValueNode value) {
-        super(StampFactory.forVoid(), array, index, elementKind);
+        super(TYPE, StampFactory.forVoid(), array, index, elementKind);
         this.value = value;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -38,12 +39,13 @@
  * comparison is an exact type comparison, not an instanceof.
  */
 @NodeInfo
-public class TypeSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
+public final class TypeSwitchNode extends SwitchNode implements LIRLowerable, Simplifiable {
 
+    public static final NodeClass<TypeSwitchNode> TYPE = NodeClass.create(TypeSwitchNode.class);
     protected final ResolvedJavaType[] keys;
 
     public TypeSwitchNode(ValueNode value, AbstractBeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
-        super(value, successors, keySuccessors, keyProbabilities);
+        super(TYPE, value, successors, keySuccessors, keyProbabilities);
         assert successors.length <= keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
         this.keys = keys;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LoweringTool.java	Sat Feb 21 19:55:33 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/PiPushable.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/PiPushable.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
 public interface PiPushable {
 
     /**
-     * 
+     *
      * @param parent PiNode
      * @return true if node was moved
      */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Sat Feb 21 19:55:33 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.*;
@@ -74,6 +73,13 @@
     StructuredGraph getMethodSubstitution(ResolvedJavaMethod method);
 
     /**
+     * Gets the method that is a substitution for a given method.
+     *
+     * @return the method, if any, that is a substitution for {@code method}
+     */
+    ResolvedJavaMethod getMethodSubstitutionMethod(ResolvedJavaMethod method);
+
+    /**
      * Gets the node class with which a method invocation should be replaced.
      *
      * @param method target of an invocation
@@ -83,11 +89,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/Virtualizable.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Sat Feb 21 19:55:33 2015 +0100
@@ -60,7 +60,7 @@
      * tool, and not directly on the node, because by the time this method is called the
      * virtualized/non-virtualized state is still speculative and might not hold because of loops,
      * etc.
-     * 
+     *
      * @param tool the tool used to describe the effects of this node
      */
     void virtualize(VirtualizerTool tool);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,7 +25,7 @@
 /**
  * This interface allows a node to convey information about what its effect would be if some of its
  * inputs were virtualized.
- * 
+ *
  * The difference to {@link VirtualizableRoot} is that removing {@link VirtualizableAllocation}
  * nodes is not considered progress during the escape analysis iterations.
  */
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,12 +25,12 @@
 /**
  * This interface allows a node to convey information about what its effect would be if some of its
  * inputs were virtualized.
- * 
+ *
  * The difference to {@link Virtualizable} is that the {@link #virtualize(VirtualizerTool)} method
  * will be called regardless of whether this node had any interaction with virtualized nodes. This
  * interface can therefore be used for object allocations, for which virtualization introduces new
  * virtualized objects.
- * 
+ *
  */
 public interface VirtualizableRoot extends Virtualizable {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizerTool.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Sat Feb 21 19:55:33 2015 +0100
@@ -242,13 +242,7 @@
 
             if (n instanceof StateSplit) {
                 FrameState state = ((StateSplit) n).stateAfter();
-                while (state != null) {
-                    ResolvedJavaMethod method = state.method();
-                    if (method != null) {
-                        elements.add(method.asStackTraceElement(state.bci - 1));
-                    }
-                    state = state.outerFrameState();
-                }
+                elements.addAll(Arrays.asList(approxSourceStackTraceElement(state)));
                 break;
             }
             n = n.predecessor();
@@ -257,14 +251,63 @@
     }
 
     /**
+     * Gets an approximate source code location for frame state.
+     *
+     * @return the StackTraceElements if an approximate source location is found, null otherwise
+     */
+    public static StackTraceElement[] approxSourceStackTraceElement(FrameState frameState) {
+        ArrayList<StackTraceElement> elements = new ArrayList<>();
+        FrameState state = frameState;
+        while (state != null) {
+            ResolvedJavaMethod method = state.method();
+            if (method != null) {
+                elements.add(method.asStackTraceElement(state.bci - 1));
+            }
+            state = state.outerFrameState();
+        }
+        return elements.toArray(new StackTraceElement[0]);
+    }
+
+    /**
      * Gets an approximate source code location for a node, encoded as an exception, if possible.
      *
      * @return the exception with the location
      */
     public static RuntimeException approxSourceException(Node node, Throwable cause) {
         final StackTraceElement[] elements = approxSourceStackTraceElement(node);
+        return createBailoutException(cause == null ? "" : cause.getMessage(), cause, elements);
+    }
+
+    /**
+     * Creates a bailout exception with the given stack trace elements and message.
+     *
+     * @param message the message of the exception
+     * @param elements the stack trace elements
+     * @return the exception
+     */
+    public static BailoutException createBailoutException(String message, Throwable cause, StackTraceElement[] elements) {
         @SuppressWarnings("serial")
-        RuntimeException exception = new RuntimeException((cause == null) ? null : cause.getMessage(), cause) {
+        BailoutException exception = new BailoutException(cause, message) {
+
+            @Override
+            public final synchronized Throwable fillInStackTrace() {
+                setStackTrace(elements);
+                return this;
+            }
+        };
+        return exception;
+    }
+
+    /**
+     * Creates a runtime exception with the given stack trace elements and message.
+     *
+     * @param message the message of the exception
+     * @param elements the stack trace elements
+     * @return the exception
+     */
+    public static RuntimeException createRuntimeException(String message, Throwable cause, StackTraceElement[] elements) {
+        @SuppressWarnings("serial")
+        RuntimeException exception = new RuntimeException(message, cause) {
 
             @Override
             public final synchronized Throwable fillInStackTrace() {
@@ -473,22 +516,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 +554,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.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.virtual;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -35,11 +36,12 @@
 @NodeInfo
 public final class AllocatedObjectNode extends FloatingNode implements Virtualizable, ArrayLengthProvider {
 
+    public static final NodeClass<AllocatedObjectNode> TYPE = NodeClass.create(AllocatedObjectNode.class);
     @Input VirtualObjectNode virtualObject;
     @Input(InputType.Extension) CommitAllocationNode commit;
 
     public AllocatedObjectNode(VirtualObjectNode virtualObject) {
-        super(StampFactory.exactNonNull(virtualObject.type()));
+        super(TYPE, StampFactory.exactNonNull(virtualObject.type()));
         this.virtualObject = virtualObject;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,13 +35,14 @@
 @NodeInfo(nameTemplate = "Alloc {i#virtualObjects}", allowedUsageTypes = {InputType.Extension})
 public final class CommitAllocationNode extends FixedWithNextNode implements VirtualizableAllocation, Lowerable, Simplifiable {
 
+    public static final NodeClass<CommitAllocationNode> TYPE = NodeClass.create(CommitAllocationNode.class);
     @Input NodeInputList<VirtualObjectNode> virtualObjects = new NodeInputList<>(this);
     @Input NodeInputList<ValueNode> values = new NodeInputList<>(this);
     @Input(InputType.Association) NodeInputList<MonitorIdNode> locks = new NodeInputList<>(this);
     protected ArrayList<Integer> lockIndexes = new ArrayList<>(Arrays.asList(0));
 
     public CommitAllocationNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     public List<VirtualObjectNode> getVirtualObjects() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EscapeObjectState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EscapeObjectState.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,12 +22,14 @@
  */
 package com.oracle.graal.nodes.virtual;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node.ValueNumberable;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
 public abstract class EscapeObjectState extends VirtualState implements ValueNumberable {
+    public static final NodeClass<EscapeObjectState> TYPE = NodeClass.create(EscapeObjectState.class);
 
     @Input protected VirtualObjectNode object;
 
@@ -35,7 +37,8 @@
         return object;
     }
 
-    public EscapeObjectState(VirtualObjectNode object) {
+    public EscapeObjectState(NodeClass<? extends EscapeObjectState> c, VirtualObjectNode object) {
+        super(c);
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -27,18 +27,20 @@
 import sun.misc.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
-public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
+public final class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
 
+    public static final NodeClass<VirtualArrayNode> TYPE = NodeClass.create(VirtualArrayNode.class);
     protected final ResolvedJavaType componentType;
     protected final int length;
 
     public VirtualArrayNode(ResolvedJavaType componentType, int length) {
-        super(componentType.getArrayClass(), true);
+        super(TYPE, componentType.getArrayClass(), true);
         this.componentType = componentType;
         this.length = length;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Sat Feb 21 19:55:33 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
@@ -23,17 +23,19 @@
 package com.oracle.graal.nodes.virtual;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 
 @NodeInfo
-public class VirtualBoxingNode extends VirtualInstanceNode {
+public final class VirtualBoxingNode extends VirtualInstanceNode {
 
+    public static final NodeClass<VirtualBoxingNode> TYPE = NodeClass.create(VirtualBoxingNode.class);
     protected final Kind boxingKind;
 
     public VirtualBoxingNode(ResolvedJavaType type, Kind boxingKind) {
-        super(type, false);
+        super(TYPE, type, false);
         this.boxingKind = boxingKind;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,12 +23,14 @@
 package com.oracle.graal.nodes.virtual;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo(nameTemplate = "VirtualInstance {p#type/s}")
 public class VirtualInstanceNode extends VirtualObjectNode {
 
+    public static final NodeClass<VirtualInstanceNode> TYPE = NodeClass.create(VirtualInstanceNode.class);
     protected final ResolvedJavaType type;
     protected final ResolvedJavaField[] fields;
 
@@ -37,7 +39,15 @@
     }
 
     public VirtualInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields, boolean hasIdentity) {
-        super(type, hasIdentity);
+        this(TYPE, type, fields, hasIdentity);
+    }
+
+    protected VirtualInstanceNode(NodeClass<? extends VirtualInstanceNode> c, ResolvedJavaType type, boolean hasIdentity) {
+        this(c, type, type.getInstanceFields(true), hasIdentity);
+    }
+
+    protected VirtualInstanceNode(NodeClass<? extends VirtualInstanceNode> c, ResolvedJavaType type, ResolvedJavaField[] fields, boolean hasIdentity) {
+        super(c, type, hasIdentity);
         this.type = type;
         this.fields = fields;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -32,10 +32,11 @@
 @NodeInfo
 public abstract class VirtualObjectNode extends ValueNode implements LIRLowerable, IterableNodeType {
 
+    public static final NodeClass<VirtualObjectNode> TYPE = NodeClass.create(VirtualObjectNode.class);
     protected boolean hasIdentity;
 
-    public VirtualObjectNode(ResolvedJavaType type, boolean hasIdentity) {
-        super(StampFactory.exactNonNull(type));
+    protected VirtualObjectNode(NodeClass<? extends VirtualObjectNode> c, ResolvedJavaType type, boolean hasIdentity) {
+        super(c, StampFactory.exactNonNull(type));
         this.hasIdentity = hasIdentity;
     }
 
--- a/graal/com.oracle.graal.options/src/com/oracle/graal/options/DerivedOptionValue.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/DerivedOptionValue.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.options;
 
+import java.io.*;
 import java.util.function.*;
 
 import com.oracle.graal.options.OptionValue.OverrideScope;
@@ -31,10 +32,13 @@
  */
 public class DerivedOptionValue<T> {
 
+    public interface OptionSupplier<T> extends Supplier<T>, Serializable {
+    }
+
     private final T initialValue;
-    private final Supplier<T> supplier;
+    private final OptionSupplier<T> supplier;
 
-    public DerivedOptionValue(Supplier<T> supplier) {
+    public DerivedOptionValue(OptionSupplier<T> supplier) {
         this.supplier = supplier;
         assert OptionValue.getOverrideScope() == null : "derived option value should be initialized outside any override scope";
         this.initialValue = createValue();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Sat Feb 21 19:55:33 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.*;
@@ -186,7 +187,7 @@
             if (node.isAlive()) {
                 METRIC_PROCESSED_NODES.increment();
 
-                NodeClass nodeClass = node.getNodeClass();
+                NodeClass<?> nodeClass = node.getNodeClass();
                 if (tryGlobalValueNumbering(node, nodeClass)) {
                     return;
                 }
@@ -212,7 +213,7 @@
             }
         }
 
-        public static boolean tryGlobalValueNumbering(Node node, NodeClass nodeClass) {
+        public static boolean tryGlobalValueNumbering(Node node, NodeClass<?> nodeClass) {
             if (nodeClass.valueNumberable() && !nodeClass.isLeafNode()) {
                 Node newNode = node.graph().findDuplicate(node);
                 if (newNode != null) {
@@ -227,7 +228,7 @@
             return false;
         }
 
-        public boolean tryCanonicalize(final Node node, NodeClass nodeClass) {
+        public boolean tryCanonicalize(final Node node, NodeClass<?> nodeClass) {
             if (customCanonicalizer != null) {
                 Node canonical = customCanonicalizer.canonicalize(node);
                 if (performReplacement(node, canonical)) {
@@ -253,7 +254,7 @@
             }
         }
 
-        public boolean baseTryCanonicalize(final Node node, NodeClass nodeClass) {
+        public boolean baseTryCanonicalize(final Node node, NodeClass<?> nodeClass) {
             if (nodeClass.isCanonicalizable()) {
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
                 try (Scope s = Debug.scope("CanonicalizeNode", node)) {
@@ -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/CleanTypeProfileProxyPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,13 +40,13 @@
     protected void run(StructuredGraph graph, PhaseContext context) {
         HashSetNodeEventListener listener = new HashSetNodeEventListener();
         try (NodeEventScope s = graph.trackNodeEvents(listener)) {
-            for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.class)) {
+            for (TypeProfileProxyNode proxy : graph.getNodes(TypeProfileProxyNode.TYPE)) {
                 graph.replaceFloating(proxy, proxy.getValue());
             }
         }
         if (!listener.getNodes().isEmpty()) {
             canonicalizer.applyIncremental(graph, context, listener.getNodes());
         }
-        assert graph.getNodes(TypeProfileProxyNode.class).count() == 0;
+        assert graph.getNodes(TypeProfileProxyNode.TYPE).count() == 0;
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Sat Feb 21 19:55:33 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();
@@ -58,22 +58,22 @@
     @Override
     protected void run(final StructuredGraph graph) {
         assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
-        if (graph.getNodes(DeoptimizeNode.class).isEmpty()) {
+        if (graph.getNodes(DeoptimizeNode.TYPE).isEmpty()) {
             return;
         }
-        for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.class)) {
+        for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) {
             assert d.isAlive();
             visitDeoptBegin(AbstractBeginNode.prevBegin(d), d.action(), d.reason(), graph);
         }
 
-        for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.class)) {
+        for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) {
 
             AbstractBeginNode pred = AbstractBeginNode.prevBegin(fixedGuard);
             if (pred instanceof AbstractMergeNode) {
                 AbstractMergeNode merge = (AbstractMergeNode) pred;
                 if (fixedGuard.condition() instanceof CompareNode) {
                     CompareNode compare = (CompareNode) fixedGuard.condition();
-                    List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+                    List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
 
                     Constant[] xs = IfNode.constantValues(compare.getX(), merge, true);
                     if (xs == null) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -79,7 +79,7 @@
         deleteNodes(flood, graph);
 
         // remove chained Merges
-        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.class)) {
+        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
             if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) {
                 graph.reduceTrivialMerge(merge);
             }
@@ -100,7 +100,7 @@
     }
 
     private static void disconnectCFGNodes(NodeFlood flood, StructuredGraph graph) {
-        for (AbstractEndNode node : graph.getNodes(AbstractEndNode.class)) {
+        for (AbstractEndNode node : graph.getNodes(AbstractEndNode.TYPE)) {
             if (!flood.isMarked(node)) {
                 AbstractMergeNode merge = node.merge();
                 if (merge != null && flood.isMarked(merge)) {
@@ -109,7 +109,7 @@
                 }
             }
         }
-        for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) {
+        for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.TYPE)) {
             if (flood.isMarked(loop)) {
                 boolean reachable = false;
                 for (LoopEndNode end : loop.loopEnds()) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,7 +40,7 @@
     @Override
     protected void run(StructuredGraph graph, MidTierContext context) {
         ControlFlowGraph cfg = null;
-        for (FrameState fs : graph.getNodes(FrameState.class)) {
+        for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
             FixedNode target = null;
             PhiNode reasonActionPhi = null;
             PhiNode speculationPhi = null;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,10 +32,10 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (ShortCircuitOrNode logic : graph.getNodes(ShortCircuitOrNode.class)) {
+        for (ShortCircuitOrNode logic : graph.getNodes(ShortCircuitOrNode.TYPE)) {
             processBinary(logic);
         }
-        assert graph.getNodes(ShortCircuitOrNode.class).isEmpty();
+        assert graph.getNodes(ShortCircuitOrNode.TYPE).isEmpty();
     }
 
     private static void processBinary(ShortCircuitOrNode binary) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -110,7 +110,7 @@
         if (graph.getGuardsStage().areFrameStatesAtSideEffects()) {
             ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null);
             graph.setGuardsStage(GuardsStage.AFTER_FSA);
-            graph.getNodes(FrameState.class).filter(state -> state.hasNoUsages()).forEach(GraphUtil::killWithUnusedFloatingInputs);
+            graph.getNodes(FrameState.TYPE).filter(state -> state.hasNoUsages()).forEach(GraphUtil::killWithUnusedFloatingInputs);
         }
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,7 +31,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (MonitorExitNode node : graph.getNodes(MonitorExitNode.class)) {
+        for (MonitorExitNode node : graph.getNodes(MonitorExitNode.TYPE)) {
             FixedNode next = node.next();
             if (next instanceof MonitorEnterNode) {
                 MonitorEnterNode monitorEnterNode = (MonitorEnterNode) next;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,7 +35,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         if (GenLoopSafepoints.getValue()) {
-            for (LoopEndNode loopEndNode : graph.getNodes(LoopEndNode.class)) {
+            for (LoopEndNode loopEndNode : graph.getNodes(LoopEndNode.TYPE)) {
                 if (loopEndNode.canSafepoint()) {
                     SafepointNode safepointNode = graph.add(new SafepointNode());
                     graph.addBeforeFixed(loopEndNode, safepointNode);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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,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;
@@ -48,11 +47,12 @@
 public class LoweringPhase extends BasePhase<PhaseContext> {
 
     @NodeInfo
-    static class DummyGuardHandle extends ValueNode implements GuardedNode {
+    static final class DummyGuardHandle extends ValueNode implements GuardedNode {
+        public static final NodeClass<DummyGuardHandle> TYPE = NodeClass.create(DummyGuardHandle.class);
         @Input(InputType.Guard) GuardingNode guard;
 
         public DummyGuardHandle(GuardingNode guard) {
-            super(StampFactory.forVoid());
+            super(TYPE, StampFactory.forVoid());
             this.guard = guard;
         }
 
@@ -120,11 +120,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/NonNullParametersPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,7 +35,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         Stamp nonNull = StampFactory.objectNonNull();
-        for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+        for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
             if (param.stamp() instanceof ObjectStamp) {
                 ObjectStamp paramStamp = (ObjectStamp) param.stamp();
                 param.setStamp(paramStamp.join(nonNull));
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchorsPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchorsPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -55,7 +55,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         LazyCFG cfg = new LazyCFG(graph);
-        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.class)) {
+        for (AbstractBeginNode begin : graph.getNodes(AbstractBeginNode.TYPE)) {
             if (!(begin instanceof StartNode || begin.predecessor() instanceof ControlSplitNode)) {
                 NodeIterable<GuardNode> guards = begin.guards();
                 if (guards.isNotEmpty()) {
@@ -71,7 +71,7 @@
                 }
             }
         }
-        for (ControlSplitNode controlSplit : graph.getNodes(ControlSplitNode.class)) {
+        for (ControlSplitNode controlSplit : graph.getNodes(ControlSplitNode.TYPE)) {
             optimizeAtControlSplit(controlSplit, cfg);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PushThroughPiPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PushThroughPiPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,7 +34,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (PiNode pi : graph.getNodes(PiNode.class)) {
+        for (PiNode pi : graph.getNodes(PiNode.TYPE)) {
             for (Node n : pi.usages().snapshot()) {
                 if (n instanceof PiPushable) {
                     PiPushable pip = (PiPushable) n;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,12 +30,12 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (ProxyNode vpn : graph.getNodes(ProxyNode.class)) {
+        for (ProxyNode vpn : graph.getNodes(ProxyNode.TYPE)) {
             if (vpn instanceof ValueProxyNode) {
                 graph.replaceFloating(vpn, vpn.value());
             }
         }
-        for (LoopExitNode exit : graph.getNodes(LoopExitNode.class)) {
+        for (LoopExitNode exit : graph.getNodes(LoopExitNode.TYPE)) {
             FrameState stateAfter = exit.stateAfter();
             if (stateAfter != null) {
                 exit.setStateAfter(null);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -62,9 +62,11 @@
     private final CanonicalizerPhase canonicalizer;
 
     @NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
-    static class DummyAnchorNode extends FixedWithNextNode implements GuardingNode, AnchoringNode {
+    static final class DummyAnchorNode extends FixedWithNextNode implements GuardingNode, AnchoringNode {
+        public static final NodeClass<DummyAnchorNode> TYPE = NodeClass.create(DummyAnchorNode.class);
+
         public DummyAnchorNode() {
-            super(StampFactory.forVoid());
+            super(TYPE, StampFactory.forVoid());
         }
 
     }
@@ -156,12 +158,12 @@
 
     @Override
     protected void run(StructuredGraph graph, PhaseContext phaseContext) {
-        if (graph.hasNode(AbstractMergeNode.class)) {
+        if (graph.hasNode(AbstractMergeNode.TYPE)) {
             ToDoubleFunction<FixedNode> nodeProbabilities = new FixedNodeProbabilityCache();
 
             // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
             // duplication.
-            for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.class).snapshot()) {
+            for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE).snapshot()) {
                 if (!(merge instanceof LoopBeginNode) && nodeProbabilities.applyAsDouble(merge) >= TailDuplicationProbability.getValue()) {
                     tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
                 }
@@ -278,11 +280,11 @@
             mergeAfter.clearEnds();
             expandDuplicated(duplicatedNodes, mergeAfter);
 
-            List<AbstractEndNode> endSnapshot = merge.forwardEnds().snapshot();
+            List<EndNode> endSnapshot = merge.forwardEnds().snapshot();
             List<PhiNode> phiSnapshot = merge.phis().snapshot();
 
             int endIndex = 0;
-            for (final AbstractEndNode forwardEnd : merge.forwardEnds()) {
+            for (final EndNode forwardEnd : merge.forwardEnds()) {
                 Map<Node, Node> duplicates;
                 if (replacements == null || replacements.get(endIndex) == null) {
                     duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), (DuplicationReplacement) null);
@@ -294,7 +296,7 @@
                 for (Map.Entry<ValueNode, PhiNode> phi : bottomPhis.entrySet()) {
                     phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey()));
                 }
-                mergeAfter.addForwardEnd((AbstractEndNode) duplicates.get(endAfter));
+                mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter));
 
                 // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding
                 // EndNode
@@ -450,8 +452,8 @@
          * @return The newly created end node.
          */
         private AbstractEndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
-            AbstractMergeNode newBottomMerge = graph.add(new MergeNode());
-            AbstractEndNode newBottomEnd = graph.add(new EndNode());
+            MergeNode newBottomMerge = graph.add(new MergeNode());
+            EndNode newBottomEnd = graph.add(new EndNode());
             newBottomMerge.addForwardEnd(newBottomEnd);
             newBottomMerge.setStateAfter(stateAfterMerge);
             ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -48,10 +48,10 @@
         }
         assert graph.getGuardsStage().areFrameStatesAtDeopts();
 
-        for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.class)) {
+        for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.TYPE)) {
             tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.reason(), deopt.getSpeculation());
         }
-        for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.class)) {
+        for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.TYPE)) {
             tryUseTrappingNullCheck(context.getMetaAccess(), deopt);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/VerifyHeapAtReturnPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/VerifyHeapAtReturnPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (ReturnNode returnNode : graph.getNodes(ReturnNode.class)) {
+        for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
             VerifyHeapNode.addBefore(returnNode);
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Sat Feb 21 19:55:33 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]);
         }
     }
@@ -323,7 +331,7 @@
             processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge, returnNodes.size() > 1);
             int callerLockDepth = stateAfter.nestedLockDepth();
             if (callerLockDepth != 0) {
-                for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
+                for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.TYPE)) {
                     MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
                     monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
                 }
@@ -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 inlined methods from inlinee to caller
+        if (inlineGraph.isInlinedMethodRecordingEnabled() && graph.isInlinedMethodRecordingEnabled()) {
+            graph.getInlinedMethods().addAll(inlineGraph.getInlinedMethods());
+        }
+
         return duplicates;
     }
 
@@ -366,11 +389,11 @@
     }
 
     private static void processSimpleInfopoints(Invoke invoke, StructuredGraph inlineGraph, Map<Node, Node> duplicates) {
-        if (inlineGraph.getNodes(SimpleInfopointNode.class).isEmpty()) {
+        if (inlineGraph.getNodes(SimpleInfopointNode.TYPE).isEmpty()) {
             return;
         }
         BytecodePosition pos = new BytecodePosition(toBytecodePosition(invoke.stateAfter()), invoke.asNode().graph().method(), invoke.bci());
-        for (SimpleInfopointNode original : inlineGraph.getNodes(SimpleInfopointNode.class)) {
+        for (SimpleInfopointNode original : inlineGraph.getNodes(SimpleInfopointNode.TYPE)) {
             SimpleInfopointNode duplicate = (SimpleInfopointNode) duplicates.get(original);
             duplicate.addCaller(pos);
         }
@@ -387,7 +410,7 @@
         FrameState stateAtReturn = invoke.stateAfter();
         FrameState outerFrameState = null;
         Kind invokeReturnKind = invoke.asNode().getKind();
-        for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+        for (FrameState original : inlineGraph.getNodes(FrameState.TYPE)) {
             FrameState frameState = (FrameState) duplicates.get(original);
             if (frameState != null && frameState.isAlive()) {
                 if (frameState.bci == BytecodeFrame.AFTER_BCI) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Sat Feb 21 19:55:33 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,12 +65,15 @@
         }
 
         InliningUtil.InlinedBytecodes.add(concrete.getCodeSize());
-        assumptions.recordMethodContents(concrete);
+        StructuredGraph graph = invoke.asNode().graph();
+        if (graph.isInlinedMethodRecordingEnabled()) {
+            graph.getInlinedMethods().add(concrete);
+        }
         return canonicalizeNodes;
     }
 
     public static void getInlinedParameterUsages(Collection<Node> parameterUsages, StructuredGraph calleeGraph, Map<Node, Node> duplicateMap) {
-        for (ParameterNode parameter : calleeGraph.getNodes(ParameterNode.class)) {
+        for (ParameterNode parameter : calleeGraph.getNodes(ParameterNode.TYPE)) {
             for (Node usage : parameter.usages()) {
                 Node node = duplicateMap.get(usage);
                 if (node != null && node.isAlive()) {
@@ -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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AssumptionInlineInfo.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/ExactInlineInfo.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/InlineInfo.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Sat Feb 21 19:55:33 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) {
@@ -376,7 +375,7 @@
             FixedNode lastSucc = successors[concretes.size()];
             for (int i = concretes.size() - 1; i >= 0; --i) {
                 LoadMethodNode method = graph.add(new LoadMethodNode(stampProvider.createMethodStamp(), concretes.get(i), receiverType, hub));
-                CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
+                LogicNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i], null);
                 IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
                 method.setNext(ifNode);
                 lastSucc = method;
@@ -465,7 +464,7 @@
         AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
         calleeEntryNode.setNext(duplicatedInvoke.asNode());
 
-        AbstractEndNode endNode = graph.add(new EndNode());
+        EndNode endNode = graph.add(new EndNode());
         duplicatedInvoke.setNext(endNode);
         returnMerge.addForwardEnd(endNode);
 
@@ -500,7 +499,7 @@
             // set new state (pop old exception object, push new one)
             newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(Kind.Object, newExceptionEdge));
 
-            AbstractEndNode endNode = graph.add(new EndNode());
+            EndNode endNode = graph.add(new EndNode());
             newExceptionEdge.setNext(endNode);
             exceptionMerge.addForwardEnd(endNode);
             exceptionObjectPhi.addInput(newExceptionEdge);
@@ -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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/TypeGuardInlineInfo.java	Sat Feb 21 19:55:33 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);
     }
@@ -106,7 +105,7 @@
         LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver));
         ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(), type.getObjectHub(), providers.getMetaAccess(), graph);
 
-        CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
+        LogicNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub, providers.getConstantReflection());
         FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
         assert invoke.predecessor() != null;
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Sat Feb 21 19:55:33 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);
     }
 
     /**
@@ -142,7 +143,7 @@
     private ArrayList<Node> replaceParamsWithMoreInformativeArguments(final Invoke invoke, final HighTierContext context) {
         NodeInputList<ValueNode> args = invoke.callTarget().arguments();
         ArrayList<Node> parameterUsages = null;
-        List<ParameterNode> params = graph.getNodes(ParameterNode.class).snapshot();
+        List<ParameterNode> params = graph.getNodes(ParameterNode.TYPE).snapshot();
         assert params.size() <= args.size();
         /*
          * param-nodes that aren't used (eg, as a result of canonicalization) don't occur in
@@ -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.isInlinedMethodRecordingEnabled()) {
+                // Don't record inlined methods in the callee 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.disableInlinedMethodRecording();
+            }
             if (context.getGraphBuilderSuite() != null) {
                 context.getGraphBuilderSuite().apply(newGraph, context);
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Sat Feb 21 19:55:33 2015 +0100
@@ -94,7 +94,7 @@
             return Collections.EMPTY_SET;
         }
         Set<ParameterNode> result = Node.newSet();
-        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+        for (ParameterNode p : graph.getNodes(ParameterNode.TYPE)) {
             if (freshlyInstantiatedArguments.get(p.index())) {
                 result.add(p);
             }
@@ -186,7 +186,7 @@
     }
 
     public boolean containsParam(ParameterNode param) {
-        for (ParameterNode p : graph.getNodes(ParameterNode.class)) {
+        for (ParameterNode p : graph.getNodes(ParameterNode.TYPE)) {
             if (p == param) {
                 return true;
             }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Sat Feb 21 19:55:33 2015 +0100
@@ -75,7 +75,7 @@
             Map<LoopBeginNode, Scope> loops = Node.newIdentityMap(EXPECTED_LOOP_COUNT);
 
             loops.put(null, new Scope(graph.start(), null));
-            for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
+            for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
                 createLoopScope(loopBegin, loops);
             }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/MethodInvocation.java	Sat Feb 21 19:55:33 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/VerifyPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/VerifyPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -54,7 +54,7 @@
 
     /**
      * Performs the actual verification.
-     * 
+     *
      * @throws VerificationError if the verification fails
      */
     protected abstract boolean verify(StructuredGraph graph, C context);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Sat Feb 21 19:55:33 2015 +0100
@@ -101,7 +101,7 @@
         if (current.predecessor() == null) {
             if (current instanceof AbstractMergeNode) {
                 AbstractMergeNode currentMerge = (AbstractMergeNode) current;
-                NodeInputList<AbstractEndNode> currentForwardEnds = currentMerge.forwardEnds();
+                NodeInputList<EndNode> currentForwardEnds = currentMerge.forwardEnds();
                 /*
                  * Use simple iteration instead of streams, since the stream infrastructure adds
                  * many frames which causes the recursion to overflow the stack earlier than it
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,7 +32,7 @@
 /**
  * Iterates over a list of nodes, which usually comes from
  * {@link SchedulePhase#getBlockToNodesMap()}.
- * 
+ *
  * While iterating, it is possible to {@link #insert(FixedNode, FixedWithNextNode) insert} and
  * {@link #replaceCurrent(FixedWithNextNode) replace} nodes.
  */
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -108,7 +108,7 @@
     protected Deque<FixedNode> getScopes(StructuredGraph graph) {
         Deque<FixedNode> result = new ArrayDeque<>();
         result.push(graph.start());
-        for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
+        for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.TYPE)) {
             result.push(loopBegin);
         }
         return result;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.compiler.common.cfg.*;
 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.cfg.*;
 import com.oracle.graal.nodes.extended.*;
@@ -306,6 +305,7 @@
     private BlockMap<List<ValueNode>> blockToNodesMap;
     private BlockMap<LocationSet> blockToKillSet;
     private final SchedulingStrategy selectedStrategy;
+    private boolean scheduleConstants;
 
     public SchedulePhase() {
         this(OptScheduleOutOfLoops.getValue() ? SchedulingStrategy.LATEST_OUT_OF_LOOPS : SchedulingStrategy.LATEST);
@@ -315,6 +315,10 @@
         this.selectedStrategy = strategy;
     }
 
+    public void setScheduleConstants(boolean value) {
+        scheduleConstants = value;
+    }
+
     @Override
     protected void run(StructuredGraph graph) {
         assert GraphOrder.assertNonCyclicGraph(graph);
@@ -450,6 +454,12 @@
         if (cfg.getNodeToBlock().containsKey(node)) {
             return;
         }
+        if (!scheduleConstants && node instanceof ConstantNode) {
+            return;
+        }
+        if (node instanceof VirtualObjectNode) {
+            return;
+        }
         // PhiNodes, ProxyNodes and FixedNodes should already have been placed in blocks by
         // ControlFlowGraph.identifyBlocks
         if (node instanceof PhiNode || node instanceof ProxyNode || node instanceof FixedNode) {
@@ -473,7 +483,7 @@
                     assert dominates(earliestBlock, block) : String.format("%s (%s) cannot be scheduled before earliest schedule (%s). location: %s", read, block, earliestBlock,
                                     read.getLocationIdentity());
                 } else {
-                    block = latestBlock(node, strategy);
+                    block = latestBlock(node, strategy, earliestBlock);
                 }
                 if (block == null) {
                     // handle nodes without usages
@@ -484,16 +494,7 @@
                     block = scheduleOutOfLoops(node, block, earliestBlock);
                 }
 
-                if (assertionEnabled()) {
-                    if (scheduleRead) {
-                        FloatingReadNode read = (FloatingReadNode) node;
-                        MemoryNode lastLocationAccess = read.getLastLocationAccess();
-                        Block upperBound = blockForMemoryNode(lastLocationAccess);
-                        assert dominates(upperBound, block) : String.format(
-                                        "out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)", read,
-                                        read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
-                    }
-                }
+                assert assertReadSchedule(node, earliestBlock, block, latest, scheduleRead);
                 break;
             default:
                 throw new GraalInternalError("unknown scheduling strategy");
@@ -505,11 +506,15 @@
         blockToNodesMap.get(block).add(node);
     }
 
-    @SuppressWarnings("all")
-    private static boolean assertionEnabled() {
-        boolean enabled = false;
-        assert enabled = true;
-        return enabled;
+    private boolean assertReadSchedule(ValueNode node, Block earliestBlock, Block block, Block latest, boolean scheduleRead) {
+        if (scheduleRead) {
+            FloatingReadNode read = (FloatingReadNode) node;
+            MemoryNode lastLocationAccess = read.getLastLocationAccess();
+            Block upperBound = blockForMemoryNode(lastLocationAccess);
+            assert dominates(upperBound, block) : String.format("out of loop movement voilated memory semantics for %s (location %s). moved to %s but upper bound is %s (earliest: %s, latest: %s)",
+                            read, read.getLocationIdentity(), block, upperBound, earliestBlock, latest);
+        }
+        return true;
     }
 
     /**
@@ -540,7 +545,7 @@
         Block earliestBlock = earliestBlock(n);
         assert dominates(upperBoundBlock, earliestBlock) : "upper bound (" + upperBoundBlock + ") should dominate earliest (" + earliestBlock + ")";
 
-        Block latestBlock = latestBlock(n, strategy);
+        Block latestBlock = latestBlock(n, strategy, earliestBlock);
         assert latestBlock != null && dominates(earliestBlock, latestBlock) : "earliest (" + earliestBlock + ") should dominate latest block (" + latestBlock + ")";
 
         Debug.log("processing %s (accessing %s): latest %s, earliest %s, upper bound %s (%s)", n, locid, latestBlock, earliestBlock, upperBoundBlock, n.getLastLocationAccess());
@@ -613,26 +618,27 @@
      * dominator of all usages. To do so all usages are also assigned to blocks.
      *
      * @param strategy
+     * @param earliestBlock
      */
-    private Block latestBlock(ValueNode node, SchedulingStrategy strategy) {
+    private Block latestBlock(ValueNode node, SchedulingStrategy strategy, Block earliestBlock) {
         CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null);
-        for (Node succ : node.successors().nonNull()) {
-            if (cfg.getNodeToBlock().get(succ) == null) {
-                throw new SchedulingError();
-            }
-            cdbc.apply(cfg.getNodeToBlock().get(succ));
-        }
         ensureScheduledUsages(node, strategy);
         for (Node usage : node.usages()) {
             blocksForUsage(node, usage, cdbc, strategy);
+            if (cdbc.block == earliestBlock) {
+                break;
+            }
         }
 
-        if (assertionEnabled()) {
-            if (cdbc.block != null && !dominates(earliestBlock(node), cdbc.block)) {
-                throw new SchedulingError("failed to find correct latest schedule for %s. cdbc: %s, earliest: %s", node, cdbc.block, earliestBlock(node));
-            }
+        assert assertLatestBlockResult(node, cdbc);
+        return cdbc.block;
+    }
+
+    private boolean assertLatestBlockResult(ValueNode node, CommonDominatorBlockClosure cdbc) throws SchedulingError {
+        if (cdbc.block != null && !dominates(earliestBlock(node), cdbc.block)) {
+            throw new SchedulingError("failed to find correct latest schedule for %s. cdbc: %s, earliest: %s", node, cdbc.block, earliestBlock(node));
         }
-        return cdbc.block;
+        return true;
     }
 
     /**
@@ -744,10 +750,8 @@
      * @param usage the usage whose blocks need to be considered
      * @param closure the closure that will be called for each block
      */
-    private void blocksForUsage(ValueNode node, Node usage, BlockClosure closure, SchedulingStrategy strategy) {
-        if (node instanceof PhiNode) {
-            throw new SchedulingError(node.toString());
-        }
+    private void blocksForUsage(ValueNode node, Node usage, CommonDominatorBlockClosure closure, SchedulingStrategy strategy) {
+        assert !(node instanceof PhiNode);
 
         if (usage instanceof PhiNode) {
             // An input to a PhiNode is used at the end of the predecessor block that corresponds to
@@ -757,19 +761,8 @@
             PhiNode phi = (PhiNode) usage;
             AbstractMergeNode merge = phi.merge();
             Block mergeBlock = cfg.getNodeToBlock().get(merge);
-            if (mergeBlock == null) {
-                throw new SchedulingError("no block for merge %s", merge.toString(Verbosity.Id));
-            }
             for (int i = 0; i < phi.valueCount(); ++i) {
                 if (phi.valueAt(i) == node) {
-                    if (mergeBlock.getPredecessorCount() <= i) {
-                        TTY.println(merge.toString());
-                        TTY.println(phi.toString());
-                        TTY.println(merge.cfgPredecessors().toString());
-                        TTY.println(mergeBlock.getPredecessors().toString());
-                        TTY.println(phi.inputs().toString());
-                        TTY.println("value count: " + phi.valueCount());
-                    }
                     closure.apply(mergeBlock.getPredecessors().get(i));
                 }
             }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,6 +23,10 @@
 package com.oracle.graal.phases.tiers;
 
 import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.lir.phases.*;
+import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.*;
+import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.*;
+import com.oracle.graal.lir.phases.AllocationPhase.*;
 import com.oracle.graal.phases.*;
 
 public interface CompilerConfiguration extends Service {
@@ -32,4 +36,10 @@
     PhaseSuite<MidTierContext> createMidTier();
 
     PhaseSuite<LowTierContext> createLowTier();
+
+    LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage();
+
+    LIRPhaseSuite<AllocationContext> createAllocationStage();
+
+    LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage();
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/HighTierContext.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/MidTierContext.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/PhaseContext.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,6 +28,7 @@
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -129,4 +130,22 @@
         return new Suites(config);
     }
 
+    public static LIRSuites createDefaultLIRSuites() {
+        String selected = CompilerConfiguration.getValue();
+        if (selected.equals("")) {
+            return new LIRSuites(defaultConfiguration.createPreAllocationOptimizationStage(), defaultConfiguration.createAllocationStage(),
+                            defaultConfiguration.createPostAllocationOptimizationStage());
+        } else {
+            return createLIRSuites(selected);
+        }
+    }
+
+    public static LIRSuites createLIRSuites(String name) {
+        CompilerConfiguration config = configurations.get(name);
+        if (config == null) {
+            throw new GraalInternalError("unknown compiler configuration: " + name);
+        }
+        return new LIRSuites(config.createPreAllocationOptimizationStage(), config.createAllocationStage(), config.createPostAllocationOptimizationStage());
+    }
+
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/SuitesProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.phases.tiers;
 
+import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.phases.*;
 
 public interface SuitesProvider {
@@ -42,4 +43,15 @@
      */
     PhaseSuite<HighTierContext> getDefaultGraphBuilderSuite();
 
+    /**
+     * Get the default phase suites of this compiler.
+     */
+    LIRSuites getDefaultLIRSuites();
+
+    /**
+     * Create a new set of low-level phase suites. Initially, the suites are the same as the
+     * {@link #getDefaultLIRSuites default} suites.
+     */
+    LIRSuites createLIRSuites();
+
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/BlockWorkList.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/BlockWorkList.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,7 +37,7 @@
 
     /**
      * Adds a block to this list in an unsorted fashion, like a stack.
-     * 
+     *
      * @param block the block to add
      */
     public void add(AbstractMergeNode block) {
@@ -55,7 +55,7 @@
     /**
      * Adds a block to this list, sorted by the supplied number. The block with the lowest number is
      * returned upon subsequent removes.
-     * 
+     *
      * @param block the block to add
      * @param number the number used to sort the block
      */
@@ -89,7 +89,7 @@
      * Removes the next block from this work list. If the blocks have been added in a sorted order,
      * then the block with the lowest number is returned. Otherwise, the last block added is
      * returned.
-     * 
+     *
      * @return the next block in the list
      */
     public AbstractMergeNode removeFromWorkList() {
@@ -101,7 +101,7 @@
 
     /**
      * Checks whether the list is empty.
-     * 
+     *
      * @return {@code true} if this list is empty
      */
     public boolean isEmpty() {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Sat Feb 21 19:55:33 2015 +0100
@@ -165,8 +165,8 @@
                             pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
                                 @Override
                                 public void apply(Node usage, Node nonVirtualNode) {
-                                    assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode : nonVirtualNode + " not available at virtualstate " + usage +
-                                                    " before " + node + " in block " + block + " \n" + list;
+                                    assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode +
+                                                    " not available at virtualstate " + usage + " before " + node + " in block " + block + " \n" + list;
                                 }
                             });
                             pendingStateAfter = null;
@@ -208,7 +208,8 @@
                                             }
                                         });
                                     } else {
-                                        assert currentState.isMarked(input) || input instanceof VirtualObjectNode : input + " not available at " + node + " in block " + block + "\n" + list;
+                                        assert currentState.isMarked(input) || input instanceof VirtualObjectNode || input instanceof ConstantNode : input + " not available at " + node +
+                                                        " in block " + block + "\n" + list;
                                     }
                                 }
                             }
@@ -217,7 +218,8 @@
                             AbstractMergeNode merge = ((AbstractEndNode) node).merge();
                             for (PhiNode phi : merge.phis()) {
                                 ValueNode phiValue = phi.valueAt((AbstractEndNode) node);
-                                assert phiValue == null || currentState.isMarked(phiValue) : phiValue + " not available at phi " + phi + " / end " + node + " in block " + block;
+                                assert phiValue == null || currentState.isMarked(phiValue) || phiValue instanceof ConstantNode : phiValue + " not available at phi " + phi + " / end " + node +
+                                                " in block " + block;
                             }
                         }
                         if (stateAfter != null) {
@@ -230,8 +232,8 @@
                         pendingStateAfter.applyToNonVirtual(new NodeClosure<Node>() {
                             @Override
                             public void apply(Node usage, Node nonVirtualNode) {
-                                assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode : nonVirtualNode + " not available at virtualstate " + usage +
-                                                " at end of block " + block + " \n" + list;
+                                assert currentState.isMarked(nonVirtualNode) || nonVirtualNode instanceof VirtualObjectNode || nonVirtualNode instanceof ConstantNode : nonVirtualNode +
+                                                " not available at virtualstate " + usage + " at end of block " + block + " \n" + list;
                             }
                         });
                     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,7 +39,7 @@
 
     @Override
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
-        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
             ResolvedJavaMethod callee = t.targetMethod();
             ResolvedJavaType debugType = context.getMetaAccess().lookupJavaType(Debug.class);
             if (callee.getDeclaringClass().equals(debugType)) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Sat Feb 21 19:55:33 2015 +0100
@@ -294,7 +294,7 @@
             writeString(type.toJavaName());
             writeByte(KLASS);
         } else if (object instanceof NodeClass) {
-            NodeClass nodeClass = (NodeClass) object;
+            NodeClass<?> nodeClass = (NodeClass<?>) object;
             writeByte(POOL_NODE_CLASS);
             writeString(nodeClass.getJavaClass().getSimpleName());
             writeString(nodeClass.getNameTemplate());
@@ -330,7 +330,7 @@
         }
     }
 
-    private void writeEdgesInfo(NodeClass nodeClass, Edges.Type type) throws IOException {
+    private void writeEdgesInfo(NodeClass<?> nodeClass, Edges.Type type) throws IOException {
         Edges edges = nodeClass.getEdges(type);
         writeShort((char) edges.getCount());
         for (int i = 0; i < edges.getCount(); i++) {
@@ -412,7 +412,7 @@
         writeInt(graph.getNodeCount());
 
         for (Node node : graph.getNodes()) {
-            NodeClass nodeClass = node.getNodeClass();
+            NodeClass<?> nodeClass = node.getNodeClass();
             node.getDebugProperties(props);
             if (probabilities != null && node instanceof FixedNode) {
                 try {
@@ -439,7 +439,7 @@
     }
 
     private void writeEdges(Node node, Edges.Type type) throws IOException {
-        NodeClass nodeClass = node.getNodeClass();
+        NodeClass<?> nodeClass = node.getNodeClass();
         Edges edges = nodeClass.getEdges(type);
         for (int i = 0; i < edges.getDirectCount(); i++) {
             writeNodeRef(edges.getNode(node, i));
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,23 +39,23 @@
  *
  * <pre>
  *     HexCodeFile ::= Platform Delim HexCode Delim (OptionalSection Delim)*
- * 
+ *
  *     OptionalSection ::= Comment | OperandComment | JumpTable | LookupTable
- * 
+ *
  *     Platform ::= "Platform" ISA WordWidth
- * 
+ *
  *     HexCode ::= "HexCode" StartAddress HexDigits
- * 
+ *
  *     Comment ::= "Comment" Position String
- * 
+ *
  *     OperandComment ::= "OperandComment" Position String
- * 
+ *
  *     JumpTable ::= "JumpTable" Position EntrySize Low High
- * 
+ *
  *     LookupTable ::= "LookupTable" Position NPairs KeySize OffsetSize
- * 
+ *
  *     Position, EntrySize, Low, High, NPairs KeySize OffsetSize ::= int
- * 
+ *
  *     Delim := "&lt;||@"
  * </pre>
  *
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64CountLeadingZerosNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64CountLeadingZerosNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -36,9 +37,10 @@
  */
 @NodeInfo
 public final class AMD64CountLeadingZerosNode extends UnaryNode implements LIRLowerable {
+    public static final NodeClass<AMD64CountLeadingZerosNode> TYPE = NodeClass.create(AMD64CountLeadingZerosNode.class);
 
     public AMD64CountLeadingZerosNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        super(TYPE, StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
         assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64CountTrailingZerosNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64CountTrailingZerosNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -36,9 +37,10 @@
  */
 @NodeInfo
 public final class AMD64CountTrailingZerosNode extends UnaryNode implements LIRLowerable {
+    public static final NodeClass<AMD64CountTrailingZerosNode> TYPE = NodeClass.create(AMD64CountTrailingZerosNode.class);
 
     public AMD64CountTrailingZerosNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        super(TYPE, StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
         assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
--- a/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.FloatConvertOp;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -38,11 +39,12 @@
  */
 @NodeInfo
 public final class AMD64FloatConvertNode extends UnaryArithmeticNode<FloatConvertOp> implements ArithmeticLIRLowerable {
+    public static final NodeClass<AMD64FloatConvertNode> TYPE = NodeClass.create(AMD64FloatConvertNode.class);
 
     protected final FloatConvert op;
 
     public AMD64FloatConvertNode(FloatConvert op, ValueNode value) {
-        super(table -> table.getFloatConvert(op), value);
+        super(TYPE, table -> table.getFloatConvert(op), value);
         this.op = op;
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Sat Feb 21 19:55:33 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,13 +330,12 @@
 
     @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);
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
     }
 
     public static final int[] constantArray3 = new int[]{1, 2, 3};
@@ -347,13 +346,12 @@
 
     @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);
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
     }
 
     public static boolean testCanonicalEqualSnippet() {
@@ -362,15 +360,14 @@
 
     @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);
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 1);
     }
 
     public static boolean testVirtualEqualSnippet() {
@@ -381,15 +378,14 @@
 
     @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);
+        Assert.assertTrue(graph.getNodes(ReturnNode.TYPE).first().result().asJavaConstant().asLong() == 0);
     }
 
     public static boolean testVirtualNotEqualSnippet(int x) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Sat Feb 21 19:55:33 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,18 +247,18 @@
      * @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);
         canonicalizer.apply(graph, context);
-        Assert.assertEquals(1, graph.getNodes(ReturnNode.class).count());
+        Assert.assertEquals(1, graph.getNodes(ReturnNode.TYPE).count());
         if (expectedClass != null) {
             if (graph.getNodes().filter(expectedClass).count() == 0) {
                 return null;
             }
         }
-        return graph.getNodes(ReturnNode.class).first().result();
+        return graph.getNodes(ReturnNode.TYPE).first().result();
     }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/CompiledExceptionHandlerTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Sat Feb 21 19:55:33 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.*;
@@ -45,16 +45,18 @@
 
     @NodeInfo
     static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
         @Input NodeInputList<ValueNode> itail;
         @Input ConstantNode i1;
         @Input FloatingNode i2;
 
         public TestNode() {
+            super(TYPE);
         }
 
     }
 
-    StructuredGraph graph = new StructuredGraph();
+    StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO);
     TestNode node;
     ConstantNode i1;
     ConstantNode i2;
@@ -113,9 +115,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Sat Feb 21 19:55:33 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/StandardMethodSubstitutionsTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -177,4 +177,25 @@
     public static double longBitsToDouble(long value) {
         return Double.longBitsToDouble(value);
     }
+
+    @SuppressWarnings("all")
+    public static boolean isInstance(Class<?> clazz) {
+        return clazz.isInstance(Number.class);
+    }
+
+    @SuppressWarnings("all")
+    public static boolean isAssignableFrom(Class<?> clazz) {
+        return clazz.isInstance(Number.class);
+    }
+
+    @Test
+    public void testClassSubstitutions() {
+        test("isInstance");
+        for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
+            for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
+                assertDeepEquals(c.isInstance(o), ClassSubstitutions.isInstance(c, o));
+                assertDeepEquals(c.isAssignableFrom(o.getClass()), ClassSubstitutions.isAssignableFrom(c, o.getClass()));
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Sat Feb 21 19:55:33 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.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Sat Feb 21 19:55:33 2015 +0100
@@ -149,7 +149,7 @@
 
     /**
      * Returns the kind from the character describing a primitive or void.
-     * 
+     *
      * @param ch the character
      * @return the kind
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ClassSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,43 @@
+/*
+ * 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.replacements;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.calc.*;
+
+/**
+ * Substitutions for {@link java.lang.Class} methods.
+ */
+@ClassSubstitution(java.lang.Class.class)
+public class ClassSubstitutions {
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isInstance(Class<?> thisObj, Object obj) {
+        return ConditionalNode.materializeIsInstance(thisObj, obj);
+    }
+
+    @MethodSubstitution(isStatic = false)
+    public static boolean isAssignableFrom(Class<?> thisClass, Class<?> otherClass) {
+        return ConditionalNode.materializeIsAssignableFrom(thisClass, otherClass);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraalMethodSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -62,6 +62,7 @@
             replacements.registerSubstitutions(Short.class, ShortSubstitutions.class);
             replacements.registerSubstitutions(UnsignedMath.class, UnsignedMathSubstitutions.class);
             replacements.registerSubstitutions(Edges.class, EdgesSubstitutions.class);
+            replacements.registerSubstitutions(Class.class, ClassSubstitutions.class);
         }
         if (Options.UseBlackholeSubstitution.getValue()) {
             replacements.registerSubstitutions(new Type() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Sat Feb 21 19:55:33 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/InstanceOfSnippetsTemplates.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/InstanceOfSnippetsTemplates.java	Sat Feb 21 19:55:33 2015 +0100
@@ -65,7 +65,7 @@
     protected abstract Arguments makeArguments(InstanceOfUsageReplacer replacer, LoweringTool tool);
 
     public void lower(FloatingNode instanceOf, LoweringTool tool) {
-        assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode;
+        assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode || instanceOf instanceof ClassIsAssignableFromNode;
         List<Node> usages = instanceOf.usages().snapshot();
 
         Instantiation instantiation = new Instantiation();
@@ -112,7 +112,7 @@
     public static final class Instantiation {
 
         private ValueNode result;
-        private CompareNode condition;
+        private LogicNode condition;
         private ValueNode trueValue;
         private ValueNode falseValue;
 
@@ -141,9 +141,9 @@
                 assert testValue.isConstant();
                 return LogicConstantNode.forBoolean(result.asConstant().equals(testValue.asConstant()), result.graph());
             }
-            if (condition == null || condition.getY() != testValue) {
+            if (condition == null || (!(condition instanceof CompareNode)) || ((CompareNode) condition).getY() != testValue) {
                 // Re-use previously generated condition if the trueValue for the test is the same
-                condition = createCompareNode(result.graph(), Condition.EQ, result, testValue);
+                condition = createCompareNode(result.graph(), Condition.EQ, result, testValue, null);
             }
             return condition;
         }
@@ -176,7 +176,7 @@
         public final ValueNode falseValue;
 
         public InstanceOfUsageReplacer(Instantiation instantiation, FloatingNode instanceOf, ValueNode trueValue, ValueNode falseValue) {
-            assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode;
+            assert instanceOf instanceof InstanceOfNode || instanceOf instanceof InstanceOfDynamicNode || instanceOf instanceof ClassIsAssignableFromNode;
             this.instantiation = instantiation;
             this.instanceOf = instanceOf;
             this.trueValue = trueValue;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java	Sat Feb 21 19:55:33 2015 +0100
@@ -80,7 +80,7 @@
 
     /**
      * Prints a formatted string to the log stream.
-     * 
+     *
      * @param format a C style printf format value that can contain at most one conversion specifier
      *            (i.e., a sequence of characters starting with '%').
      * @param value the value associated with the conversion specifier
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -64,7 +64,7 @@
     @Override
     protected void run(StructuredGraph graph) {
         ArrayList<Node> cleanUpReturnList = new ArrayList<>();
-        for (MethodCallTargetNode node : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode node : graph.getNodes(MethodCallTargetNode.TYPE)) {
             tryIntrinsify(node, cleanUpReturnList);
         }
 
@@ -80,21 +80,12 @@
 
         NodeIntrinsic intrinsic = getIntrinsic(target);
         if (intrinsic != null) {
-            assert target.getAnnotation(Fold.class) == null;
-            assert target.isStatic() : "node intrinsic must be static: " + target;
-
-            ResolvedJavaType[] parameterTypes = resolveJavaTypes(target.toParameterTypes(), declaringClass);
-
-            // Prepare the arguments for the reflective constructor call on the node class.
-            Object[] nodeConstructorArguments = prepareArguments(methodCallTargetNode, parameterTypes, target, false);
-            if (nodeConstructorArguments == null) {
+            Stamp stamp = methodCallTargetNode.invoke().asNode().stamp();
+            Node newInstance = createIntrinsicNode(methodCallTargetNode.arguments(), stamp, target, graph, intrinsic);
+            if (newInstance == null) {
                 return false;
             }
 
-            // Create the new node instance.
-            ResolvedJavaType c = getNodeClass(target, intrinsic);
-            Node newInstance = createNodeInstance(graph, c, parameterTypes, methodCallTargetNode.invoke().asNode().stamp(), intrinsic.setStampFromReturnType(), nodeConstructorArguments);
-
             // Replace the invoke with the new node.
             newInstance = graph.addOrUnique(newInstance);
             methodCallTargetNode.invoke().intrinsify(newInstance);
@@ -103,21 +94,10 @@
             cleanUpReturnList.add(newInstance);
         } else if (isFoldable(target)) {
             ResolvedJavaType[] parameterTypes = resolveJavaTypes(target.toParameterTypes(), declaringClass);
-
-            // Prepare the arguments for the reflective method call
-            JavaConstant[] arguments = (JavaConstant[]) prepareArguments(methodCallTargetNode, parameterTypes, target, true);
-            if (arguments == null) {
+            JavaConstant constant = tryFold(methodCallTargetNode.arguments(), parameterTypes, target);
+            if (constant != null && constant.equals(COULD_NOT_FOLD)) {
                 return false;
             }
-            JavaConstant receiver = null;
-            if (!methodCallTargetNode.isStatic()) {
-                receiver = arguments[0];
-                arguments = Arrays.copyOfRange(arguments, 1, arguments.length);
-                parameterTypes = Arrays.copyOfRange(parameterTypes, 1, parameterTypes.length);
-            }
-
-            // Call the method
-            JavaConstant constant = target.invoke(receiver, arguments);
 
             if (constant != null) {
                 // Replace the invoke with the result of the call
@@ -134,17 +114,83 @@
         return true;
     }
 
+    @SuppressWarnings("serial") public static final JavaConstant COULD_NOT_FOLD = new PrimitiveConstant(Kind.Illegal, 100) {
+        @Override
+        public boolean equals(Object o) {
+            return this == o;
+        }
+    };
+
+    public JavaConstant tryFold(List<ValueNode> args, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target) {
+        JavaConstant[] reflectArgs = (JavaConstant[]) prepareArguments(args, parameterTypes, target, true);
+        if (reflectArgs == null) {
+            return COULD_NOT_FOLD;
+        }
+        JavaConstant receiver = null;
+        if (!target.isStatic()) {
+            receiver = reflectArgs[0];
+            reflectArgs = Arrays.copyOfRange(reflectArgs, 1, reflectArgs.length);
+        }
+
+        // Call the method
+        return target.invoke(receiver, reflectArgs);
+    }
+
+    private static boolean areAllConstant(List<ValueNode> arguments) {
+        for (ValueNode arg : arguments) {
+            if (!arg.isConstant()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Attempts to create a node to replace a call to a {@link NodeIntrinsic} annotated method.
+     *
+     * @param arguments the arguments of the call
+     * @param stamp the stamp to use for the returned node
+     * @param method the method annotated with {@link NodeIntrinsic}
+     * @param graph the graph into which the created node will be added
+     * @return a {@link ConstantNode} if the intrinsic could be
+     *         {@linkplain NodeIntrinsic#foldable() folded}, {@code null} if intrinsification could
+     *         not (yet) be performed, otherwise the node representing the intrinsic
+     */
+    public ValueNode createIntrinsicNode(List<ValueNode> arguments, Stamp stamp, ResolvedJavaMethod method, StructuredGraph graph, NodeIntrinsic intrinsic) {
+        assert method.getAnnotation(Fold.class) == null;
+        assert method.isStatic() : "node intrinsic must be static: " + method;
+
+        ResolvedJavaType[] parameterTypes = resolveJavaTypes(method.toParameterTypes(), method.getDeclaringClass());
+
+        if (intrinsic.foldable() && areAllConstant(arguments)) {
+            JavaConstant res = tryFold(arguments, parameterTypes, method);
+            if (!res.equals(COULD_NOT_FOLD)) {
+                return ConstantNode.forConstant(res, providers.getMetaAccess());
+            }
+        }
+
+        // Prepare the arguments for the reflective constructor call on the node class.
+        Object[] nodeConstructorArguments = prepareArguments(arguments, parameterTypes, method, false);
+        if (nodeConstructorArguments == null) {
+            return null;
+        }
+
+        // Create the new node instance.
+        ResolvedJavaType c = getNodeClass(method, intrinsic);
+        return createNodeInstance(graph, c, parameterTypes, stamp, intrinsic.setStampFromReturnType(), nodeConstructorArguments);
+    }
+
     /**
      * Permits a subclass to override the default definition of "intrinsic".
      */
-    protected NodeIntrinsic getIntrinsic(ResolvedJavaMethod method) {
+    public NodeIntrinsic getIntrinsic(ResolvedJavaMethod method) {
         return method.getAnnotation(Node.NodeIntrinsic.class);
     }
 
     /**
      * Permits a subclass to override the default definition of "foldable".
      */
-    protected boolean isFoldable(ResolvedJavaMethod method) {
+    public boolean isFoldable(ResolvedJavaMethod method) {
         return method.getAnnotation(Fold.class) != null;
     }
 
@@ -156,12 +202,11 @@
      * @return the arguments for the reflective invocation or null if an argument of {@code invoke}
      *         that is expected to be constant isn't
      */
-    private Object[] prepareArguments(MethodCallTargetNode methodCallTargetNode, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
-        NodeInputList<ValueNode> arguments = methodCallTargetNode.arguments();
+    private Object[] prepareArguments(List<ValueNode> arguments, ResolvedJavaType[] parameterTypes, ResolvedJavaMethod target, boolean folding) {
         Object[] reflectionCallArguments = folding ? new JavaConstant[arguments.size()] : new Object[arguments.size()];
         for (int i = 0; i < reflectionCallArguments.length; ++i) {
             int parameterIndex = i;
-            if (!methodCallTargetNode.isStatic()) {
+            if (!target.isStatic()) {
                 parameterIndex--;
             }
             ValueNode argument = arguments.get(i);
@@ -171,34 +216,41 @@
                 }
                 ConstantNode constantNode = (ConstantNode) argument;
                 Constant constant = constantNode.asConstant();
-                ResolvedJavaType type = providers.getConstantReflection().asJavaType(constant);
+                /*
+                 * For intrinsification (but not for folding) if we have a Class<?> object we want
+                 * the corresponding ResolvedJavaType.
+                 */
+                ResolvedJavaType type = folding ? null : providers.getConstantReflection().asJavaType(constant);
+                Object arg;
                 if (type != null) {
-                    reflectionCallArguments[i] = type;
+                    /* If we found such a type then it's our arg */
+                    arg = type;
                     parameterTypes[i] = providers.getMetaAccess().lookupJavaType(ResolvedJavaType.class);
                 } else {
                     JavaConstant javaConstant = (JavaConstant) constant;
-                    if (parameterTypes[i].getKind() == Kind.Boolean) {
-                        reflectionCallArguments[i] = Boolean.valueOf(javaConstant.asInt() != 0);
-                    } else if (parameterTypes[i].getKind() == Kind.Byte) {
-                        reflectionCallArguments[i] = Byte.valueOf((byte) javaConstant.asInt());
-                    } else if (parameterTypes[i].getKind() == Kind.Short) {
-                        reflectionCallArguments[i] = Short.valueOf((short) javaConstant.asInt());
-                    } else if (parameterTypes[i].getKind() == Kind.Char) {
-                        reflectionCallArguments[i] = Character.valueOf((char) javaConstant.asInt());
-                    } else if (parameterTypes[i].getKind() == Kind.Object) {
-                        if (!folding) {
-                            reflectionCallArguments[i] = snippetReflection.asObject(parameterTypes[i], javaConstant);
+                    if (folding) {
+                        /* For folding we want JavaConstants */
+                        arg = javaConstant;
+                    } else {
+                        /* For intrinsification we want want corresponding objects */
+                        if (parameterTypes[i].getKind() == Kind.Boolean) {
+                            arg = Boolean.valueOf(javaConstant.asInt() != 0);
+                        } else if (parameterTypes[i].getKind() == Kind.Byte) {
+                            arg = Byte.valueOf((byte) javaConstant.asInt());
+                        } else if (parameterTypes[i].getKind() == Kind.Short) {
+                            arg = Short.valueOf((short) javaConstant.asInt());
+                        } else if (parameterTypes[i].getKind() == Kind.Char) {
+                            arg = Character.valueOf((char) javaConstant.asInt());
+                        } else if (parameterTypes[i].getKind() == Kind.Object) {
+                            arg = snippetReflection.asObject(parameterTypes[i], javaConstant);
                         } else {
-                            reflectionCallArguments[i] = javaConstant;
+                            arg = javaConstant.asBoxedPrimitive();
                         }
-                    } else {
-                        reflectionCallArguments[i] = javaConstant.asBoxedPrimitive();
                     }
                 }
-                if (folding && reflectionCallArguments[i] != constant) {
-                    assert !(reflectionCallArguments[i] instanceof JavaConstant);
-                    reflectionCallArguments[i] = snippetReflection.forObject(reflectionCallArguments[i]);
-                }
+
+                assert folding || !(arg instanceof JavaConstant);
+                reflectionCallArguments[i] = arg;
             } else {
                 reflectionCallArguments[i] = argument;
                 parameterTypes[i] = providers.getMetaAccess().lookupJavaType(ValueNode.class);
@@ -219,7 +271,7 @@
         return result;
     }
 
-    protected Node createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
+    protected ValueNode createNodeInstance(StructuredGraph graph, ResolvedJavaType nodeClass, ResolvedJavaType[] parameterTypes, Stamp invokeStamp, boolean setStampFromReturnType,
                     Object[] nodeConstructorArguments) {
         ResolvedJavaMethod constructor = null;
         Object[] arguments = null;
@@ -241,7 +293,7 @@
         }
 
         try {
-            ValueNode intrinsicNode = (ValueNode) snippetReflection.invoke(constructor, null, arguments);
+            ValueNode intrinsicNode = (ValueNode) invokeConstructor(constructor, arguments);
 
             if (setStampFromReturnType) {
                 intrinsicNode.setStamp(invokeStamp);
@@ -252,6 +304,10 @@
         }
     }
 
+    protected Object invokeConstructor(ResolvedJavaMethod constructor, Object[] arguments) {
+        return snippetReflection.invoke(constructor, null, arguments);
+    }
+
     private static String sigString(ResolvedJavaType[] types) {
         StringBuilder sb = new StringBuilder("(");
         for (int i = 0; i < types.length; i++) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -43,7 +43,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (MethodCallTargetNode n : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode n : graph.getNodes(MethodCallTargetNode.TYPE)) {
             checkInvoke(n);
         }
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Sat Feb 21 19:55:33 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,7 @@
     public final Providers providers;
     public final SnippetReflectionProvider snippetReflection;
     public final TargetDescription target;
-    public final Assumptions assumptions;
+    public final NodeIntrinsificationPhase nodeIntrinsificationPhase;
 
     /**
      * The preprocessed replacement graphs.
@@ -219,15 +220,15 @@
     // 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();
+        this.nodeIntrinsificationPhase = createNodeIntrinsificationPhase();
     }
 
     private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true"));
@@ -286,8 +287,8 @@
 
         // Do deferred intrinsification of node intrinsics
 
-        createNodeIntrinsificationPhase().apply(specializedSnippet);
-        new CanonicalizerPhase(true).apply(specializedSnippet, new PhaseContext(providers, assumptions));
+        nodeIntrinsificationPhase.apply(specializedSnippet);
+        new CanonicalizerPhase(true).apply(specializedSnippet, new PhaseContext(providers));
         NodeIntrinsificationVerificationPhase.verify(specializedSnippet);
     }
 
@@ -319,10 +320,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();
@@ -536,7 +533,7 @@
          * Does final processing of a snippet graph.
          */
         protected void finalizeGraph(StructuredGraph graph) {
-            replacements.createNodeIntrinsificationPhase().apply(graph);
+            replacements.nodeIntrinsificationPhase.apply(graph);
             if (!SnippetTemplate.hasConstantParameter(method)) {
                 NodeIntrinsificationVerificationPhase.verify(graph);
             }
@@ -612,20 +609,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.disableInlinedMethodRecording();
+
             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 +636,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 +660,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));
             }
         }
 
@@ -665,10 +668,10 @@
          * Called after all inlining for a given graph is complete.
          */
         protected void afterInlining(StructuredGraph graph) {
-            replacements.createNodeIntrinsificationPhase().apply(graph);
+            replacements.nodeIntrinsificationPhase.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));
             }
         }
 
@@ -678,7 +681,7 @@
             final StructuredGraph graph = buildInitialGraph(methodToParse);
             try (Scope s = Debug.scope("buildGraph", graph)) {
                 Set<MethodCallTargetNode> doNotInline = null;
-                for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
                     if (doNotInline != null && doNotInline.contains(callTarget)) {
                         continue;
                     }
@@ -734,7 +737,7 @@
 
                 afterInlining(graph);
 
-                for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
+                for (LoopEndNode end : graph.getNodes(LoopEndNode.TYPE)) {
                     end.disableSafepoint();
                 }
 
@@ -827,6 +830,12 @@
     }
 
     @Override
+    public ResolvedJavaMethod getMethodSubstitutionMethod(ResolvedJavaMethod original) {
+        ClassReplacements cr = getClassReplacements(original.getDeclaringClass().getName());
+        return cr == null ? null : cr.methodSubstitutions.get(original);
+    }
+
+    @Override
     public void registerSnippetTemplateCache(SnippetTemplateCache templates) {
         assert snippetTemplateCache.get(templates.getClass().getName()) == null;
         snippetTemplateCache.put(templates.getClass().getName(), templates);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Sat Feb 21 19:55:33 2015 +0100
@@ -45,10 +45,12 @@
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 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.*;
@@ -391,12 +393,13 @@
     }
 
     @NodeInfo
-    static class VarargsPlaceholderNode extends FloatingNode implements ArrayLengthProvider {
+    static final class VarargsPlaceholderNode extends FloatingNode implements ArrayLengthProvider {
 
+        public static final NodeClass<VarargsPlaceholderNode> TYPE = NodeClass.create(VarargsPlaceholderNode.class);
         protected final Varargs varargs;
 
         public VarargsPlaceholderNode(Varargs varargs, MetaAccessProvider metaAccess) {
-            super(StampFactory.exactNonNull(metaAccess.lookupJavaType(varargs.componentType).getArrayClass()));
+            super(TYPE, StampFactory.exactNonNull(metaAccess.lookupJavaType(varargs.componentType).getArrayClass()));
             this.varargs = varargs;
         }
 
@@ -561,10 +564,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.isInlinedMethodRecordingEnabled()) {
+            snippetCopy.disableInlinedMethodRecording();
+        }
+
         Map<Node, Node> nodeReplacements = Node.newIdentityMap();
         nodeReplacements.put(snippetGraph.start(), snippetCopy.start());
 
@@ -731,7 +738,7 @@
         } else {
             snippetCopy.addAfterFixed(snippetCopy.start(), memoryAnchor);
         }
-        List<ReturnNode> returnNodes = snippet.getNodes(ReturnNode.class).snapshot();
+        List<ReturnNode> returnNodes = snippet.getNodes(ReturnNode.TYPE).snapshot();
         if (returnNodes.isEmpty()) {
             this.returnNode = null;
         } else if (returnNodes.size() == 1) {
@@ -1214,7 +1221,7 @@
             Node stampDup = duplicates.get(stampNode);
             ((ValueNode) stampDup).setStamp(replacee.stamp());
         }
-        for (ParameterNode paramNode : snippet.getNodes(ParameterNode.class)) {
+        for (ParameterNode paramNode : snippet.getNodes(ParameterNode.TYPE)) {
             for (Node usage : paramNode.usages()) {
                 Node usageDup = duplicates.get(usage);
                 propagateStamp(usageDup);
@@ -1245,7 +1252,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();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,280 @@
+/*
+ * 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.replacements;
+
+import static com.oracle.graal.api.code.MemoryBarriers.*;
+import static com.oracle.graal.java.GraphBuilderContext.*;
+import static java.lang.Character.*;
+import sun.misc.*;
+
+import com.oracle.graal.api.directives.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.InvocationPlugin;
+import com.oracle.graal.java.InvocationPlugins.Registration;
+import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.debug.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * Provides non-runtime specific {@link InvocationPlugin}s.
+ */
+public class StandardGraphBuilderPlugins {
+
+    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        registerObjectPlugins(metaAccess, plugins);
+        registerMathPlugins(metaAccess, plugins);
+        registerUnsafePlugins(metaAccess, plugins);
+        registerGraalDirectivesPlugins(metaAccess, plugins);
+    }
+
+    public static void registerUnsafePlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Unsafe.class);
+        for (Kind kind : Kind.values()) {
+            if ((kind.isPrimitive() && kind != Kind.Void) || kind == Kind.Object) {
+                String kindName = kind.getJavaName();
+                kindName = toUpperCase(kindName.charAt(0)) + kindName.substring(1);
+                String getName = "get" + kindName;
+                String putName = "put" + kindName;
+                r.register3(getName, Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, false));
+                r.register4(putName, Receiver.class, Object.class, long.class, kind == Kind.Object ? Object.class : kind.toJavaClass(), new UnsafePutPlugin(kind, false));
+                r.register3(getName + "Volatile", Receiver.class, Object.class, long.class, new UnsafeGetPlugin(kind, true));
+                r.register4(putName + "Volatile", Receiver.class, Object.class, long.class, kind == Kind.Object ? Object.class : kind.toJavaClass(), new UnsafePutPlugin(kind, true));
+                if (kind != Kind.Boolean && kind != Kind.Object) {
+                    r.register2(getName, Receiver.class, long.class, new UnsafeGetPlugin(kind, false));
+                    r.register3(putName, Receiver.class, long.class, kind.toJavaClass(), new UnsafePutPlugin(kind, false));
+                }
+            }
+        }
+    }
+
+    public static void registerMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, Math.class);
+        r.register1("abs", Float.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.push(Kind.Float, builder.append(new AbsNode(value)));
+                return true;
+            }
+        });
+        r.register1("abs", Double.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.push(Kind.Double, builder.append(new AbsNode(value)));
+                return true;
+            }
+        });
+        r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.push(Kind.Double, builder.append(new SqrtNode(value)));
+                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);
+            }
+        }
+    }
+
+    public static void registerObjectPlugins(MetaAccessProvider metaAccess, InvocationPlugins 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;
+            }
+        });
+    }
+
+    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, InvocationPlugins 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, InvocationPlugins plugins) {
+            String name = kind.toJavaClass().getSimpleName() + "Value";
+            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
+            plugins.register(method, this);
+        }
+    }
+
+    static class UnsafeGetPlugin implements InvocationPlugin {
+
+        private final Kind returnKind;
+        private final boolean isVolatile;
+
+        public UnsafeGetPlugin(Kind returnKind, boolean isVolatile) {
+            this.returnKind = returnKind;
+            this.isVolatile = isVolatile;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode address) {
+            builder.push(returnKind.getStackKind(), builder.append(new DirectReadNode(address, returnKind)));
+            return true;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) {
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_PRE_VOLATILE_READ));
+            }
+            builder.push(returnKind.getStackKind(), builder.append(new UnsafeLoadNode(object, offset, returnKind, LocationIdentity.ANY_LOCATION)));
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_POST_VOLATILE_READ));
+            }
+            return true;
+        }
+    }
+
+    static class UnsafePutPlugin implements InvocationPlugin {
+
+        private final Kind kind;
+        private final boolean isVolatile;
+
+        public UnsafePutPlugin(Kind kind, boolean isVolatile) {
+            this.kind = kind;
+            this.isVolatile = isVolatile;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) {
+            builder.append(new DirectStoreNode(address, value, kind));
+            return true;
+        }
+
+        public boolean apply(GraphBuilderContext builder, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            }
+            builder.append(new UnsafeStoreNode(object, offset, value, kind, LocationIdentity.ANY_LOCATION));
+            if (isVolatile) {
+                builder.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
+            }
+            return true;
+        }
+    }
+
+    public static void registerGraalDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, GraalDirectives.class);
+        r.register0("deoptimize", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
+                return true;
+            }
+        });
+
+        r.register0("inCompiledCode", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.push(Kind.Int, builder.append(ConstantNode.forInt(1)));
+                return true;
+            }
+        });
+
+        r.register0("controlFlowAnchor", new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder) {
+                builder.append(new ControlFlowAnchorNode());
+                return true;
+            }
+        });
+
+        r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
+                builder.push(Kind.Int, builder.append(new BranchProbabilityNode(probability, condition)));
+                return true;
+            }
+        });
+
+        InvocationPlugin blackholePlugin = new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                builder.append(new BlackholeNode(value));
+                return true;
+            }
+        };
+
+        for (Kind kind : Kind.values()) {
+            Class<?> cls = null;
+            switch (kind) {
+                case Object:
+                    cls = Object.class;
+                    break;
+                case Void:
+                case Illegal:
+                    continue;
+                default:
+                    cls = kind.toJavaClass();
+            }
+
+            r.register1("blackhole", cls, blackholePlugin);
+
+            final Kind stackKind = kind.getStackKind();
+            r.register1("opaque", cls, new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                    builder.push(stackKind, builder.append(new OpaqueNode(value)));
+                    return true;
+                }
+            });
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,6 +38,7 @@
 @NodeInfo
 public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
 
+    public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class);
     /** {@link Kind} of the arrays to compare. */
     protected final Kind kind;
 
@@ -51,8 +52,9 @@
     @Input ValueNode length;
 
     public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length) {
-        super(StampFactory.forKind(Kind.Boolean));
-        assert array1.stamp().equals(array2.stamp());
+        super(TYPE, StampFactory.forKind(Kind.Boolean));
+        // Ignore nullness in stamp equality test
+        assert array1.stamp().join(StampFactory.objectNonNull()).equals(array2.stamp().join(StampFactory.objectNonNull()));
         ObjectStamp array1Stamp = (ObjectStamp) array1.stamp();
         ResolvedJavaType componentType = array1Stamp.type().getComponentType();
         this.kind = componentType.getKind();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,13 +38,14 @@
 @NodeInfo
 public final class AssertionNode extends FixedWithNextNode implements Lowerable, Canonicalizable, LIRLowerable {
 
+    public static final NodeClass<AssertionNode> TYPE = NodeClass.create(AssertionNode.class);
     @Input ValueNode value;
 
     protected final boolean compileTimeAssertion;
     protected final String message;
 
     public AssertionNode(boolean compileTimeAssertion, ValueNode value, String message) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.value = value;
         this.compileTimeAssertion = compileTimeAssertion;
         this.message = message;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.spi.*;
@@ -31,10 +32,12 @@
 import com.oracle.graal.nodes.virtual.*;
 
 @NodeInfo
-public class BasicArrayCopyNode extends MacroStateSplitNode implements Virtualizable {
+public abstract class BasicArrayCopyNode extends MacroStateSplitNode implements Virtualizable {
 
-    public BasicArrayCopyNode(Invoke invoke) {
-        super(invoke);
+    public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
+
+    public BasicArrayCopyNode(NodeClass<? extends BasicArrayCopyNode> c, Invoke invoke) {
+        super(c, invoke);
     }
 
     protected ValueNode getSource() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
@@ -35,10 +36,12 @@
 import com.oracle.graal.nodes.virtual.*;
 
 @NodeInfo
-public class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider {
+public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider {
 
-    public BasicObjectCloneNode(Invoke invoke) {
-        super(invoke);
+    public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class);
+
+    protected BasicObjectCloneNode(NodeClass<? extends BasicObjectCloneNode> c, Invoke invoke) {
+        super(c, invoke);
     }
 
     @Override
@@ -61,7 +64,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 +108,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/BitCountNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -34,8 +35,10 @@
 @NodeInfo
 public final class BitCountNode extends UnaryNode implements LIRLowerable {
 
+    public static final NodeClass<BitCountNode> TYPE = NodeClass.create(BitCountNode.class);
+
     public BitCountNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        super(TYPE, StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
         assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -38,8 +39,10 @@
 @NodeInfo
 public final class BitScanForwardNode extends UnaryNode implements LIRLowerable {
 
+    public static final NodeClass<BitScanForwardNode> TYPE = NodeClass.create(BitScanForwardNode.class);
+
     public BitScanForwardNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        super(TYPE, StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
         assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -38,8 +39,10 @@
 @NodeInfo
 public final class BitScanReverseNode extends UnaryNode implements LIRLowerable {
 
+    public static final NodeClass<BitScanReverseNode> TYPE = NodeClass.create(BitScanReverseNode.class);
+
     public BitScanReverseNode(ValueNode value) {
-        super(StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
+        super(TYPE, StampFactory.forInteger(Kind.Int, 0, ((PrimitiveStamp) value.stamp()).getBits()), value);
         assert value.getKind() == Kind.Int || value.getKind() == Kind.Long;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -40,6 +40,7 @@
  */
 @NodeInfo
 public final class DeferredPiNode extends FloatingNode implements Canonicalizable {
+    public static final NodeClass<DeferredPiNode> TYPE = NodeClass.create(DeferredPiNode.class);
 
     @Input ValueNode object;
     @Input ValueNode type;
@@ -49,7 +50,7 @@
     }
 
     public DeferredPiNode(ValueNode type, ValueNode object) {
-        super(StampFactory.object());
+        super(TYPE, StampFactory.object());
         this.type = type;
         this.object = object;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.HeapAccess.BarrierType;
@@ -37,6 +38,7 @@
 @NodeInfo
 public final class DirectObjectStoreNode extends FixedWithNextNode implements Lowerable {
 
+    public static final NodeClass<DirectObjectStoreNode> TYPE = NodeClass.create(DirectObjectStoreNode.class);
     @Input ValueNode object;
     @Input ValueNode value;
     @Input ValueNode offset;
@@ -45,7 +47,7 @@
     protected final Kind storeKind;
 
     public DirectObjectStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value, LocationIdentity locationIdentity, Kind storeKind) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.object = object;
         this.value = value;
         this.offset = offset;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -36,13 +37,14 @@
  * {@link StateSplit} and takes a computed address instead of an object.
  */
 @NodeInfo
-public class DirectReadNode extends FixedWithNextNode implements LIRLowerable {
+public final class DirectReadNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<DirectReadNode> TYPE = NodeClass.create(DirectReadNode.class);
     @Input protected ValueNode address;
     protected final Kind readKind;
 
     public DirectReadNode(ValueNode address, Kind readKind) {
-        super(StampFactory.forKind(readKind.getStackKind()));
+        super(TYPE, StampFactory.forKind(readKind.getStackKind()));
         this.address = address;
         this.readKind = readKind;
     }
@@ -52,9 +54,9 @@
     }
 
     /**
-     * If we are sub it sizes, we try to sign/zero extend the value to at least int as it is done in
-     * the {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#implicitLoadConvert} and
-     * {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#createUnsafeRead}.
+     * If we are sub int sizes, we try to sign/zero extend the value to at least int as it is done
+     * in the {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#implicitLoadConvert}
+     * and {@link com.oracle.graal.replacements.DefaultJavaLoweringProvider#createUnsafeRead}.
      *
      * @see com.oracle.graal.replacements.DefaultJavaLoweringProvider#implicitLoadConvert
      * @see com.oracle.graal.replacements.DefaultJavaLoweringProvider#createUnsafeRead
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -36,14 +37,15 @@
  * {@link StateSplit} and takes a computed address instead of an object.
  */
 @NodeInfo
-public class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
+public final class DirectStoreNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<DirectStoreNode> TYPE = NodeClass.create(DirectStoreNode.class);
     @Input protected ValueNode address;
     @Input protected ValueNode value;
     protected final Kind kind;
 
     public DirectStoreNode(ValueNode address, ValueNode value, Kind kind) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.address = address;
         this.value = value;
         this.kind = kind;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,9 +38,10 @@
  */
 @NodeInfo
 public final class ExplodeLoopNode extends FixedWithNextNode {
+    public static final NodeClass<ExplodeLoopNode> TYPE = NodeClass.create(ExplodeLoopNode.class);
 
     public ExplodeLoopNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     public LoopBeginNode findLoopBegin() {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -33,14 +33,15 @@
  * Implements the semantics of {@link VarargsParameter}.
  */
 @NodeInfo
-public class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable {
+public final class LoadSnippetVarargParameterNode extends FixedWithNextNode implements Canonicalizable {
 
+    public static final NodeClass<LoadSnippetVarargParameterNode> TYPE = NodeClass.create(LoadSnippetVarargParameterNode.class);
     @Input ValueNode index;
 
     @Input NodeInputList<ParameterNode> parameters;
 
     public LoadSnippetVarargParameterNode(ParameterNode[] locals, ValueNode index, Stamp stamp) {
-        super(stamp);
+        super(TYPE, stamp);
         this.index = index;
         this.parameters = new NodeInputList<>(this, locals);
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,8 +57,9 @@
  * </ul>
  */
 @NodeInfo
-public class MacroNode extends FixedWithNextNode implements Lowerable {
+public abstract class MacroNode extends FixedWithNextNode implements Lowerable {
 
+    public static final NodeClass<MacroNode> TYPE = NodeClass.create(MacroNode.class);
     @Input protected NodeInputList<ValueNode> arguments;
 
     protected final int bci;
@@ -66,8 +67,8 @@
     protected final JavaType returnType;
     protected final InvokeKind invokeKind;
 
-    public MacroNode(Invoke invoke) {
-        super(StampFactory.forKind(((MethodCallTargetNode) invoke.callTarget()).targetMethod().getSignature().getReturnKind()));
+    protected MacroNode(NodeClass<? extends MacroNode> c, Invoke invoke) {
+        super(c, StampFactory.forKind(((MethodCallTargetNode) invoke.callTarget()).targetMethod().getSignature().getReturnKind()));
         MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
         this.arguments = new NodeInputList<>(this, methodCallTarget.arguments());
         this.bci = invoke.bci();
@@ -129,7 +130,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.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
@@ -35,12 +36,13 @@
  * {@link MemoryCheckpoint}.
  */
 @NodeInfo
-public class MacroStateSplitNode extends MacroNode implements StateSplit, MemoryCheckpoint.Single {
+public abstract class MacroStateSplitNode extends MacroNode implements StateSplit, MemoryCheckpoint.Single {
 
+    public static final NodeClass<MacroStateSplitNode> TYPE = NodeClass.create(MacroStateSplitNode.class);
     @OptionalInput(InputType.State) protected FrameState stateAfter;
 
-    public MacroStateSplitNode(Invoke invoke) {
-        super(invoke);
+    public MacroStateSplitNode(NodeClass<? extends MacroStateSplitNode> c, Invoke invoke) {
+        super(c, invoke);
         this.stateAfter = invoke.stateAfter();
     }
 
@@ -64,7 +66,7 @@
     }
 
     protected void replaceSnippetInvokes(StructuredGraph snippetGraph) {
-        for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode call : snippetGraph.getNodes(MethodCallTargetNode.TYPE)) {
             Invoke invoke = call.invoke();
             if (!call.targetMethod().equals(getTargetMethod())) {
                 throw new GraalInternalError("unexpected invoke %s in snippet", getClass().getSimpleName());
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,8 +34,9 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class MathIntrinsicNode extends UnaryNode implements ArithmeticLIRLowerable {
+public final class MathIntrinsicNode extends UnaryNode implements ArithmeticLIRLowerable {
 
+    public static final NodeClass<MathIntrinsicNode> TYPE = NodeClass.create(MathIntrinsicNode.class);
     protected final Operation operation;
 
     public enum Operation {
@@ -50,7 +52,7 @@
     }
 
     public MathIntrinsicNode(ValueNode value, Operation op) {
-        super(StampFactory.forKind(Kind.Double), value);
+        super(TYPE, StampFactory.forKind(Kind.Double), value);
         assert value.stamp() instanceof FloatStamp && PrimitiveStamp.getBits(value.stamp()) == 64;
         this.operation = op;
     }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -22,15 +22,18 @@
  */
 package com.oracle.graal.replacements.nodes;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 
 @NodeInfo
-public class MathPowNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
+public final class MathPowNode extends MacroStateSplitNode implements Canonicalizable.Binary<ValueNode> {
+
+    public static final NodeClass<MathPowNode> TYPE = NodeClass.create(MathPowNode.class);
 
     public MathPowNode(Invoke i) {
-        super(i);
+        super(TYPE, i);
     }
 
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java	Sat Feb 21 19:55:33 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
@@ -31,10 +31,12 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(allowedUsageTypes = {InputType.Memory})
-public class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
+public final class MemoryAnchorNode extends FixedWithNextNode implements LIRLowerable, MemoryNode, Canonicalizable {
+
+    public static final NodeClass<MemoryAnchorNode> TYPE = NodeClass.create(MemoryAnchorNode.class);
 
     public MemoryAnchorNode() {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
     }
 
     public void generate(NodeLIRBuilderTool generator) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -35,8 +35,10 @@
 @NodeInfo
 public abstract class PureFunctionMacroNode extends MacroStateSplitNode implements Canonicalizable {
 
-    public PureFunctionMacroNode(Invoke invoke) {
-        super(invoke);
+    public static final NodeClass<PureFunctionMacroNode> TYPE = NodeClass.create(PureFunctionMacroNode.class);
+
+    protected PureFunctionMacroNode(NodeClass<? extends PureFunctionMacroNode> c, Invoke invoke) {
+        super(c, invoke);
     }
 
     /**
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,8 +34,9 @@
  * Access the value of a specific register.
  */
 @NodeInfo(nameTemplate = "ReadRegister %{p#register}")
-public class ReadRegisterNode extends FixedWithNextNode implements LIRLowerable {
+public final class ReadRegisterNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<ReadRegisterNode> TYPE = NodeClass.create(ReadRegisterNode.class);
     /**
      * The fixed register to access.
      */
@@ -54,7 +56,7 @@
     protected final boolean incoming;
 
     public ReadRegisterNode(Register register, Kind kind, boolean directUse, boolean incoming) {
-        super(StampFactory.forKind(kind));
+        super(TYPE, StampFactory.forKind(kind));
         assert register != null;
         this.register = register;
         this.directUse = directUse;
@@ -62,7 +64,7 @@
     }
 
     public ReadRegisterNode(Register register, boolean directUse, boolean incoming) {
-        super(StampFactory.forNodeIntrinsic());
+        super(TYPE, StampFactory.forNodeIntrinsic());
         assert register != null;
         this.register = register;
         this.directUse = directUse;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2014, 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
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -32,10 +33,12 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class ReverseBytesNode extends UnaryNode implements LIRLowerable {
+public final class ReverseBytesNode extends UnaryNode implements LIRLowerable {
+
+    public static final NodeClass<ReverseBytesNode> TYPE = NodeClass.create(ReverseBytesNode.class);
 
     public ReverseBytesNode(ValueNode value) {
-        super(StampFactory.forKind(value.getKind()), value);
+        super(TYPE, StampFactory.forKind(value.getKind()), value);
         assert getKind() == Kind.Int || getKind() == Kind.Long;
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,6 +25,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -33,8 +34,9 @@
  * Changes the value of a specific register.
  */
 @NodeInfo(nameTemplate = "WriteRegister %{p#register}")
-public class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable {
+public final class WriteRegisterNode extends FixedWithNextNode implements LIRLowerable {
 
+    public static final NodeClass<WriteRegisterNode> TYPE = NodeClass.create(WriteRegisterNode.class);
     /**
      * The fixed register to access.
      */
@@ -46,7 +48,7 @@
     @Input ValueNode value;
 
     public WriteRegisterNode(Register register, ValueNode value) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.register = register;
         this.value = value;
     }
--- a/graal/com.oracle.graal.runtime/src/com/oracle/graal/runtime/RuntimeProvider.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.runtime/src/com/oracle/graal/runtime/RuntimeProvider.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,7 +37,7 @@
 
     /**
      * Gets the backend for a given architecture.
-     * 
+     *
      * @param arch a specific architecture class
      */
     <T extends Architecture> Backend getBackend(Class<T> arch);
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Sat Feb 21 19:55:33 2015 +0100
@@ -45,7 +45,9 @@
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.java.*;
 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.*;
@@ -96,12 +98,23 @@
                 }
             }
         });
-        compileQueue = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+        int selectedProcessors = TruffleCompilerOptions.TruffleCompilerThreads.getValue();
+        if (selectedProcessors == 0) {
+            // No manual selection made, check how many processors are available.
+            int availableProcessors = Runtime.getRuntime().availableProcessors();
+            if (availableProcessors >= 4) {
+                selectedProcessors = 2;
+            } else if (availableProcessors >= 12) {
+                selectedProcessors = 4;
+            }
+        }
+        selectedProcessors = Math.max(1, selectedProcessors);
+        compileQueue = new ThreadPoolExecutor(selectedProcessors, selectedProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
 
     }
 
     private static void installOptimizedCallTargetCallDirect() {
-        if (TruffleCompilerOptions.TruffleFunctionInlining.getValue()) {
+        if (TruffleCompilerOptions.TruffleFunctionInlining.getValue() && !TruffleCompilerOptions.FastPE.getValue()) {
             ((HotSpotResolvedJavaMethod) getGraalProviders().getMetaAccess().lookupJavaMethod(OptimizedCallTarget.getCallDirectMethod())).setNotInlineable();
         }
     }
@@ -175,16 +188,16 @@
         MetaAccessProvider metaAccess = providers.getMetaAccess();
         SuitesProvider suitesProvider = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites();
         Suites suites = suitesProvider.createSuites();
+        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, new CompilationResult(), factory);
+                        suites, lirSuites, new CompilationResult(), factory);
     }
 
     private static Providers getGraalProviders() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/CompilerAssertsTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,91 @@
+/*
+ * 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.truffle.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.truffle.test.nodes.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+public class CompilerAssertsTest extends PartialEvaluationTest {
+
+    public static class NeverPartOfCompilationTestNode extends AbstractTestNode {
+
+        @Override
+        public int execute(VirtualFrame frame) {
+            CompilerAsserts.neverPartOfCompilation();
+            return 0;
+        }
+
+    }
+
+    public static class CompilationConstantTestNode extends AbstractTestNode {
+        @Child private AbstractTestNode child;
+
+        public CompilationConstantTestNode(AbstractTestNode child) {
+            this.child = child;
+        }
+
+        @Override
+        public int execute(VirtualFrame frame) {
+            CompilerAsserts.compilationConstant(child.execute(frame));
+            return 0;
+        }
+
+    }
+
+    @Test
+    public void neverPartOfCompilationTest() {
+        NeverPartOfCompilationTestNode result = new NeverPartOfCompilationTestNode();
+        RootTestNode rootNode = new RootTestNode(new FrameDescriptor(), "neverPartOfCompilation", result);
+        try {
+            compileHelper("neverPartOfCompilation", rootNode, new Object[0]);
+            Assert.fail("Expected bailout exception due to never part of compilation");
+        } catch (BailoutException e) {
+            // Bailout exception expected.
+        }
+    }
+
+    @Test
+    public void compilationNonConstantTest() {
+        FrameDescriptor descriptor = new FrameDescriptor();
+        CompilationConstantTestNode result = new CompilationConstantTestNode(new NonConstantTestNode(5));
+        RootTestNode rootNode = new RootTestNode(descriptor, "compilationConstant", result);
+        try {
+            compileHelper("compilationConstant", rootNode, new Object[0]);
+            Assert.fail("Expected bailout exception because expression is not compilation constant");
+        } catch (BailoutException e) {
+            // Bailout exception expected.
+        }
+    }
+
+    @Test
+    public void compilationConstantTest() {
+        FrameDescriptor descriptor = new FrameDescriptor();
+        CompilationConstantTestNode result = new CompilationConstantTestNode(new ConstantTestNode(5));
+        RootTestNode rootNode = new RootTestNode(descriptor, "compilationConstant", result);
+        compileHelper("compilationConstant", rootNode, new Object[0]);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,187 @@
+/*
+ * 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.truffle.test;
+
+import org.junit.*;
+
+import com.oracle.graal.truffle.test.nodes.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.impl.*;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Tests for a single simple PE test with various combinations of instrumentation attached. None of
+ * the instrumentation ultimate does anything, so should compile away.
+ */
+public class InstrumentationPartialEvaluationTest extends PartialEvaluationTest {
+
+    public static Object constant42() {
+        return 42;
+    }
+
+    @Test
+    public void constantValueUninstrumented() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedNoInstruments() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        result.probe();
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedNullInstrument() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument");
+        probe.attach(instrument);
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedNullInstrumentDisposed() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument = Instrument.create(new DefaultEventListener(), "Null test Instrument");
+        probe.attach(instrument);
+        instrument.dispose();
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedTwoNullInstruments() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1");
+        probe.attach(instrument1);
+        Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2");
+        probe.attach(instrument2);
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedThreeNullInstruments() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1");
+        probe.attach(instrument1);
+        Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2");
+        probe.attach(instrument2);
+        Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3");
+        probe.attach(instrument3);
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void constantValueProbedThreeNullInstrumentsOneDisposed() {
+        FrameDescriptor fd = new FrameDescriptor();
+        AbstractTestNode result = new ConstantTestNode(42);
+        RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        root.adoptChildren();
+        Probe probe = result.probe();
+        Instrument instrument1 = Instrument.create(new DefaultEventListener(), "Null test Instrument 1");
+        probe.attach(instrument1);
+        Instrument instrument2 = Instrument.create(new DefaultEventListener(), "Null test Instrument 2");
+        probe.attach(instrument2);
+        Instrument instrument3 = Instrument.create(new DefaultEventListener(), "Null test Instrument 3");
+        probe.attach(instrument3);
+        instrument2.dispose();
+        assertPartialEvalEquals("constant42", root);
+    }
+
+    @Test
+    public void instrumentDeopt() {
+        final FrameDescriptor fd = new FrameDescriptor();
+        final AbstractTestNode result = new ConstantTestNode(42);
+        final RootTestNode root = new RootTestNode(fd, "constantValue", result);
+        final Probe[] probe = new Probe[1];
+        final int[] count = {1};
+        count[0] = 0;
+        // Register a "prober" that will get applied when CallTarget gets created.
+        Probe.registerASTProber(new ASTProber() {
+
+            @Override
+            public void probeAST(Node node) {
+                node.accept(new NodeVisitor() {
+
+                    @Override
+                    public boolean visit(Node visitedNode) {
+                        if (visitedNode instanceof ConstantTestNode) {
+                            probe[0] = visitedNode.probe();
+                        }
+                        return true;
+                    }
+
+                });
+            }
+        });
+        final RootCallTarget callTarget = Truffle.getRuntime().createCallTarget(root);
+
+        // The CallTarget has one Probe, attached to the ConstantTestNode, ready to run
+        Assert.assertEquals(42, callTarget.call()); // Correct result
+        Assert.assertEquals(0, count[0]);           // Didn't count anything
+
+        // Add a counting instrument; this changes the "Probe state" and should cause a deopt
+        final Instrument countingInstrument = Instrument.create(new DefaultEventListener() {
+
+            @Override
+            public void enter(Node node, VirtualFrame frame) {
+                count[0] = count[0] + 1;
+            }
+        });
+        probe[0].attach(countingInstrument);
+
+        Assert.assertEquals(42, callTarget.call()); // Correct result
+        Assert.assertEquals(1, count[0]);           // Counted the first call
+
+        // Remove the counting instrument; this changes the "Probe state" and should cause a deopt
+        countingInstrument.dispose();
+
+        Assert.assertEquals(42, callTarget.call()); // Correct result
+        Assert.assertEquals(1, count[0]);           // Didn't count this time
+
+    }
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Sat Feb 21 19:55:33 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,40 +74,39 @@
     }
 
     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)) {
+        for (MethodCallTargetNode node : actual.getNodes(MethodCallTargetNode.TYPE)) {
             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);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
     }
 
     protected void removeFrameStates(StructuredGraph graph) {
-        for (FrameState frameState : graph.getNodes(FrameState.class)) {
+        for (FrameState frameState : graph.getNodes(FrameState.TYPE)) {
             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.test/src/com/oracle/graal/truffle/test/nodes/AbstractTestNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/AbstractTestNode.java	Sat Feb 21 19:55:33 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
@@ -23,6 +23,7 @@
 package com.oracle.graal.truffle.test.nodes;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
 import com.oracle.truffle.api.nodes.*;
 
 public abstract class AbstractTestNode extends Node {
@@ -31,5 +32,15 @@
         super(null);
     }
 
+    @Override
+    public boolean isInstrumentable() {
+        return true;
+    }
+
+    @Override
+    public WrapperNode createWrapperNode() {
+        return new WrapperTestNode(this);
+    }
+
     public abstract int execute(VirtualFrame frame);
 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
 
     @Children private final AbstractTestNode[] statements;
 
-    public BlockTestNode(AbstractTestNode[] statements) {
+    public BlockTestNode(AbstractTestNode... statements) {
         this.statements = statements;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/NonConstantTestNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle.test.nodes;
+
+import com.oracle.truffle.api.frame.*;
+
+public class NonConstantTestNode extends AbstractTestNode {
+
+    private int value;
+
+    public NonConstantTestNode(int value) {
+        this.value = value;
+    }
+
+    @Override
+    public int execute(VirtualFrame frame) {
+        return value;
+    }
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/RootTestNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/RootTestNode.java	Sat Feb 21 19:55:33 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
@@ -23,6 +23,7 @@
 package com.oracle.graal.truffle.test.nodes;
 
 import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
 import com.oracle.truffle.api.nodes.*;
 
 @NodeInfo
@@ -43,6 +44,11 @@
     }
 
     @Override
+    public void applyInstrumentation() {
+        Probe.applyASTProbers(node);
+    }
+
+    @Override
     public String toString() {
         return name;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/WrapperTestNode.java	Sat Feb 21 19:55:33 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.graal.truffle.test.nodes;
+
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.instrument.*;
+import com.oracle.truffle.api.instrument.ProbeNode.WrapperNode;
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Support for PE testing instrumentation.
+ */
+public final class WrapperTestNode extends AbstractTestNode implements WrapperNode {
+
+    @Child private AbstractTestNode child;
+    @Child private ProbeNode probeNode;
+
+    public WrapperTestNode(AbstractTestNode child) {
+        this.child = child;
+    }
+
+    public String instrumentationInfo() {
+        return "Wrapper for PE test nodes";
+    }
+
+    @Override
+    public boolean isInstrumentable() {
+        return false;
+    }
+
+    public void insertProbe(ProbeNode newProbeNode) {
+        this.probeNode = newProbeNode;
+    }
+
+    public Probe getProbe() {
+        return probeNode.getProbe();
+    }
+
+    @Override
+    public Node getChild() {
+        return child;
+    }
+
+    @Override
+    public int execute(VirtualFrame frame) {
+        probeNode.enter(child, frame);
+        try {
+            final int result = child.execute(frame);
+            probeNode.returnValue(child, frame, result);
+            return result;
+        } catch (KillException e) {
+            throw (e);
+        } catch (Exception e) {
+            probeNode.returnExceptional(child, frame, e);
+            throw (e);
+        }
+
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithBoxing.java	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import sun.misc.*;
+
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.frame.*;
+
+/**
+ * More efficient implementation of the Truffle frame that has no safety checks for frame accesses
+ * and therefore is much faster. Should not be used during debugging as potential misuses of the
+ * frame object would show up very late and would be hard to identify.
+ */
+public final class FrameWithBoxing implements VirtualFrame, MaterializedFrame {
+    private final FrameDescriptor descriptor;
+    private final Object[] arguments;
+    private Object[] locals;
+
+    public FrameWithBoxing(FrameDescriptor descriptor, Object[] arguments) {
+        this.descriptor = descriptor;
+        this.arguments = arguments;
+        int size = descriptor.getSize();
+        this.locals = new Object[size];
+        Object defaultValue = descriptor.getDefaultValue();
+        if (defaultValue != null) {
+            Arrays.fill(locals, defaultValue);
+        }
+    }
+
+    @Override
+    public Object[] getArguments() {
+        return unsafeCast(arguments, Object[].class, true, true);
+    }
+
+    @Override
+    public MaterializedFrame materialize() {
+        return this;
+    }
+
+    @Override
+    public Object getObject(FrameSlot slot) {
+        int index = slot.getIndex();
+        Object[] curLocals = this.getLocals();
+        if (CompilerDirectives.inInterpreter() && index >= curLocals.length) {
+            curLocals = resizeAndCheck(slot);
+        }
+        return curLocals[index];
+    }
+
+    private Object[] getLocals() {
+        return unsafeCast(locals, Object[].class, true, true);
+    }
+
+    @Override
+    public void setObject(FrameSlot slot, Object value) {
+        int index = slot.getIndex();
+        Object[] curLocals = this.getLocals();
+        if (CompilerDirectives.inInterpreter() && index >= curLocals.length) {
+            curLocals = resizeAndCheck(slot);
+        }
+        curLocals[index] = value;
+    }
+
+    @Override
+    public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
+        Object result = getObject(slot);
+        if (CompilerDirectives.inInterpreter() && !(result instanceof Byte)) {
+            throw new FrameSlotTypeException();
+        }
+        return (Byte) result;
+    }
+
+    @Override
+    public void setByte(FrameSlot slot, byte value) {
+        setObject(slot, value);
+    }
+
+    @Override
+    public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
+        Object result = getObject(slot);
+        if (CompilerDirectives.inInterpreter() && !(result instanceof Boolean)) {
+            throw new FrameSlotTypeException();
+        }
+        return (Boolean) result;
+    }
+
+    @Override
+    public void setBoolean(FrameSlot slot, boolean value) {
+        setObject(slot, value);
+    }
+
+    @Override
+    public float getFloat(FrameSlot slot) throws FrameSlotTypeException {
+        Object result = getObject(slot);
+        if (CompilerDirectives.inInterpreter() && !(result instanceof Float)) {
+            throw new FrameSlotTypeException();
+        }
+        return (Float) result;
+    }
+
+    @Override
+    public void setFloat(FrameSlot slot, float value) {
+        setObject(slot, value);
+    }
+
+    @Override
+    public long getLong(FrameSlot slot) throws FrameSlotTypeException {
+        Object result = getObject(slot);
+        if (CompilerDirectives.inInterpreter() && !(result instanceof Long)) {
+            throw new FrameSlotTypeException();
+        }
+        return (Long) result;
+    }
+
+    @Override
+    public void setLong(FrameSlot slot, long value) {
+        setObject(slot, value);
+    }
+
+    @Override
+    public int getInt(FrameSlot slot) throws FrameSlotTypeException {
+        Object result = getObject(slot);
+        if (CompilerDirectives.inInterpreter() && !(result instanceof Integer)) {
+            throw new FrameSlotTypeException();
+        }
+        return (Integer) result;
+    }
+
+    @Override
+    public void setInt(FrameSlot slot, int value) {
+        setObject(slot, value);
+    }
+
+    @Override
+    public double getDouble(FrameSlot slot) throws FrameSlotTypeException {
+        Object result = getObject(slot);
+        if (CompilerDirectives.inInterpreter() && !(result instanceof Double)) {
+            throw new FrameSlotTypeException();
+        }
+        return (Double) result;
+    }
+
+    @Override
+    public void setDouble(FrameSlot slot, double value) {
+        setObject(slot, value);
+    }
+
+    @Override
+    public FrameDescriptor getFrameDescriptor() {
+        return this.descriptor;
+    }
+
+    private Object[] resizeAndCheck(FrameSlot slot) {
+        if (!resize()) {
+            throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+        }
+        return locals;
+    }
+
+    @Override
+    public Object getValue(FrameSlot slot) {
+        return getObject(slot);
+    }
+
+    private boolean resize() {
+        int oldSize = locals.length;
+        int newSize = descriptor.getSize();
+        if (newSize > oldSize) {
+            locals = Arrays.copyOf(locals, newSize);
+            Arrays.fill(locals, oldSize, newSize, descriptor.getDefaultValue());
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isObject(FrameSlot slot) {
+        return getObject(slot) != null;
+    }
+
+    @Override
+    public boolean isByte(FrameSlot slot) {
+        return getObject(slot) instanceof Byte;
+    }
+
+    @Override
+    public boolean isBoolean(FrameSlot slot) {
+        return getObject(slot) instanceof Boolean;
+    }
+
+    @Override
+    public boolean isInt(FrameSlot slot) {
+        return getObject(slot) instanceof Integer;
+    }
+
+    @Override
+    public boolean isLong(FrameSlot slot) {
+        return getObject(slot) instanceof Long;
+    }
+
+    @Override
+    public boolean isFloat(FrameSlot slot) {
+        return getObject(slot) instanceof Float;
+    }
+
+    @Override
+    public boolean isDouble(FrameSlot slot) {
+        return getObject(slot) instanceof Double;
+    }
+
+    @SuppressWarnings({"unchecked", "unused"})
+    static <T> T unsafeCast(Object value, Class<T> type, boolean condition, boolean nonNull) {
+        return (T) value;
+    }
+
+    @SuppressWarnings("unused")
+    static int unsafeGetInt(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getInt(receiver, offset);
+    }
+
+    @SuppressWarnings("unused")
+    static long unsafeGetLong(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getLong(receiver, offset);
+    }
+
+    @SuppressWarnings("unused")
+    static float unsafeGetFloat(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getFloat(receiver, offset);
+    }
+
+    @SuppressWarnings("unused")
+    static double unsafeGetDouble(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getDouble(receiver, offset);
+    }
+
+    @SuppressWarnings("unused")
+    static Object unsafeGetObject(Object receiver, long offset, boolean condition, Object locationIdentity) {
+        return UNSAFE.getObject(receiver, offset);
+    }
+
+    @SuppressWarnings("unused")
+    static void unsafePutInt(Object receiver, long offset, int value, Object locationIdentity) {
+        UNSAFE.putInt(receiver, offset, value);
+    }
+
+    @SuppressWarnings("unused")
+    static void unsafePutLong(Object receiver, long offset, long value, Object locationIdentity) {
+        UNSAFE.putLong(receiver, offset, value);
+    }
+
+    @SuppressWarnings("unused")
+    static void unsafePutFloat(Object receiver, long offset, float value, Object locationIdentity) {
+        UNSAFE.putFloat(receiver, offset, value);
+    }
+
+    @SuppressWarnings("unused")
+    static void unsafePutDouble(Object receiver, long offset, double value, Object locationIdentity) {
+        UNSAFE.putDouble(receiver, offset, value);
+    }
+
+    @SuppressWarnings("unused")
+    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.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Sat Feb 21 19:55:33 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.*;
 
@@ -43,6 +41,25 @@
     private Object[] locals;
     private long[] primitiveLocals;
     private byte[] tags;
+    public static final byte OBJECT_TAG = 0;
+    public static final byte ILLEGAL_TAG = 1;
+    public static final byte LONG_TAG = 2;
+    public static final byte INT_TAG = 3;
+    public static final byte DOUBLE_TAG = 4;
+    public static final byte FLOAT_TAG = 5;
+    public static final byte BOOLEAN_TAG = 6;
+    public static final byte BYTE_TAG = 7;
+
+    static {
+        assert OBJECT_TAG == FrameSlotKind.Object.tag;
+        assert ILLEGAL_TAG == FrameSlotKind.Illegal.tag;
+        assert LONG_TAG == FrameSlotKind.Long.tag;
+        assert INT_TAG == FrameSlotKind.Int.tag;
+        assert DOUBLE_TAG == FrameSlotKind.Double.tag;
+        assert FLOAT_TAG == FrameSlotKind.Float.tag;
+        assert BOOLEAN_TAG == FrameSlotKind.Boolean.tag;
+        assert BYTE_TAG == FrameSlotKind.Byte.tag;
+    }
 
     public FrameWithoutBoxing(FrameDescriptor descriptor, Object[] arguments) {
         this.descriptor = descriptor;
@@ -69,8 +86,9 @@
 
     @Override
     public Object getObject(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Object);
-        return getObjectUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, OBJECT_TAG);
+        return getObjectUnsafe(slotIndex, slot);
     }
 
     private Object[] getLocals() {
@@ -85,156 +103,168 @@
         return unsafeCast(tags, byte[].class, true, true);
     }
 
-    private Object getObjectUnsafe(FrameSlot slot) {
-        int slotIndex = slot.getIndex();
-        return unsafeGetObject(getLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, this.getTags()[slotIndex] == FrameSlotKind.Object.ordinal(), slot);
+    private Object getObjectUnsafe(int slotIndex, FrameSlot slot) {
+        return unsafeGetObject(getLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, this.getTags()[slotIndex] == FrameSlotKind.Object.tag, slot);
     }
 
     @Override
     public void setObject(FrameSlot slot, Object value) {
-        verifySet(slot, FrameSlotKind.Object);
-        setObjectUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, OBJECT_TAG);
+        setObjectUnsafe(slotIndex, slot, value);
     }
 
-    private void setObjectUnsafe(FrameSlot slot, Object value) {
-        unsafePutObject(getLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slot.getIndex() * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, slot);
+    private void setObjectUnsafe(int slotIndex, FrameSlot slot, Object value) {
+        unsafePutObject(getLocals(), Unsafe.ARRAY_OBJECT_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_OBJECT_INDEX_SCALE, value, slot);
     }
 
     @Override
     public byte getByte(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Byte);
-        return getByteUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, BYTE_TAG);
+        return getByteUnsafe(slotIndex, slot);
     }
 
-    private byte getByteUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Byte);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Byte.ordinal();
-        return unsafeGetByte(getPrimitiveLocals(), offset, condition, slot);
+    private byte getByteUnsafe(int slotIndex, FrameSlot slot) {
+        long offset = getPrimitiveOffset(slotIndex);
+        boolean condition = this.getTags()[slotIndex] == FrameSlotKind.Byte.tag;
+        return (byte) unsafeGetInt(getPrimitiveLocals(), offset, condition, slot);
     }
 
     @Override
     public void setByte(FrameSlot slot, byte value) {
-        verifySet(slot, FrameSlotKind.Byte);
-        setByteUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, BYTE_TAG);
+        setByteUnsafe(slotIndex, slot, value);
     }
 
-    private void setByteUnsafe(FrameSlot slot, byte value) {
-        long offset = alignPrimitive(slot, Kind.Boolean);
-        unsafePutByte(getPrimitiveLocals(), offset, value, slot);
+    private void setByteUnsafe(int slotIndex, FrameSlot slot, byte value) {
+        long offset = getPrimitiveOffset(slotIndex);
+        unsafePutInt(getPrimitiveLocals(), offset, value, slot);
     }
 
     @Override
     public boolean getBoolean(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Boolean);
-        return getBooleanUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, BOOLEAN_TAG);
+        return getBooleanUnsafe(slotIndex, slot);
     }
 
-    private boolean getBooleanUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Boolean);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Boolean.ordinal();
-        return unsafeGetBoolean(getPrimitiveLocals(), offset, condition, slot);
+    private boolean getBooleanUnsafe(int slotIndex, FrameSlot slot) {
+        long offset = getPrimitiveOffset(slotIndex);
+        boolean condition = this.getTags()[slotIndex] == FrameSlotKind.Boolean.tag;
+        return unsafeGetInt(getPrimitiveLocals(), offset, condition, slot) != 0;
     }
 
     @Override
     public void setBoolean(FrameSlot slot, boolean value) {
-        verifySet(slot, FrameSlotKind.Boolean);
-        setBooleanUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, BOOLEAN_TAG);
+        setBooleanUnsafe(slotIndex, slot, value);
     }
 
-    private void setBooleanUnsafe(FrameSlot slot, boolean value) {
-        long offset = alignPrimitive(slot, Kind.Boolean);
-        unsafePutBoolean(getPrimitiveLocals(), offset, value, slot);
+    private void setBooleanUnsafe(int slotIndex, FrameSlot slot, boolean value) {
+        long offset = getPrimitiveOffset(slotIndex);
+        unsafePutInt(getPrimitiveLocals(), offset, value ? 1 : 0, slot);
     }
 
     @Override
     public float getFloat(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Float);
-        return getFloatUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, FLOAT_TAG);
+        return getFloatUnsafe(slotIndex, slot);
     }
 
-    private float getFloatUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Float);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Float.ordinal();
+    private float getFloatUnsafe(int slotIndex, FrameSlot slot) {
+        long offset = getPrimitiveOffset(slotIndex);
+        boolean condition = this.getTags()[slotIndex] == FrameSlotKind.Float.tag;
         return unsafeGetFloat(getPrimitiveLocals(), offset, condition, slot);
     }
 
     @Override
     public void setFloat(FrameSlot slot, float value) {
-        verifySet(slot, FrameSlotKind.Float);
-        setFloatUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, FLOAT_TAG);
+        setFloatUnsafe(slotIndex, slot, value);
     }
 
-    private void setFloatUnsafe(FrameSlot slot, float value) {
-        long offset = alignPrimitive(slot, Kind.Float);
+    private void setFloatUnsafe(int slotIndex, FrameSlot slot, float value) {
+        long offset = getPrimitiveOffset(slotIndex);
         unsafePutFloat(getPrimitiveLocals(), offset, value, slot);
     }
 
     @Override
     public long getLong(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Long);
-        return getLongUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, LONG_TAG);
+        return getLongUnsafe(slotIndex, slot);
     }
 
-    private long getLongUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Long);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Long.ordinal();
+    private long getLongUnsafe(int slotIndex, FrameSlot slot) {
+        long offset = getPrimitiveOffset(slotIndex);
+        boolean condition = this.getTags()[slotIndex] == FrameSlotKind.Long.tag;
         return unsafeGetLong(getPrimitiveLocals(), offset, condition, slot);
     }
 
     @Override
     public void setLong(FrameSlot slot, long value) {
-        verifySet(slot, FrameSlotKind.Long);
-        setLongUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, LONG_TAG);
+        setLongUnsafe(slotIndex, slot, value);
     }
 
-    private void setLongUnsafe(FrameSlot slot, long value) {
-        long offset = alignPrimitive(slot, Kind.Long);
+    private void setLongUnsafe(int slotIndex, FrameSlot slot, long value) {
+        long offset = getPrimitiveOffset(slotIndex);
         unsafePutLong(getPrimitiveLocals(), offset, value, slot);
     }
 
     @Override
     public int getInt(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Int);
-        return getIntUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, INT_TAG);
+        return getIntUnsafe(slotIndex, slot);
     }
 
-    private int getIntUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Int);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Int.ordinal();
+    private int getIntUnsafe(int slotIndex, FrameSlot slot) {
+        long offset = getPrimitiveOffset(slotIndex);
+        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Int.tag;
         return unsafeGetInt(getPrimitiveLocals(), offset, condition, slot);
     }
 
     @Override
     public void setInt(FrameSlot slot, int value) {
-        verifySet(slot, FrameSlotKind.Int);
-        setIntUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, INT_TAG);
+        setIntUnsafe(slotIndex, slot, value);
     }
 
-    private void setIntUnsafe(FrameSlot slot, int value) {
-        long offset = alignPrimitive(slot, Kind.Int);
+    private void setIntUnsafe(int slotIndex, FrameSlot slot, int value) {
+        long offset = getPrimitiveOffset(slotIndex);
         unsafePutInt(getPrimitiveLocals(), offset, value, slot);
     }
 
     @Override
     public double getDouble(FrameSlot slot) throws FrameSlotTypeException {
-        verifyGet(slot, FrameSlotKind.Double);
-        return getDoubleUnsafe(slot);
+        int slotIndex = slot.getIndex();
+        verifyGet(slotIndex, DOUBLE_TAG);
+        return getDoubleUnsafe(slotIndex, slot);
     }
 
-    private double getDoubleUnsafe(FrameSlot slot) {
-        long offset = alignPrimitive(slot, Kind.Double);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Double.ordinal();
+    private double getDoubleUnsafe(int slotIndex, FrameSlot slot) {
+        long offset = getPrimitiveOffset(slotIndex);
+        boolean condition = this.getTags()[slotIndex] == FrameSlotKind.Double.tag;
         return unsafeGetDouble(getPrimitiveLocals(), offset, condition, slot);
     }
 
     @Override
     public void setDouble(FrameSlot slot, double value) {
-        verifySet(slot, FrameSlotKind.Double);
-        setDoubleUnsafe(slot, value);
+        int slotIndex = slot.getIndex();
+        verifySet(slotIndex, DOUBLE_TAG);
+        setDoubleUnsafe(slotIndex, slot, value);
     }
 
-    private void setDoubleUnsafe(FrameSlot slot, double value) {
-        long offset = alignPrimitive(slot, Kind.Double);
+    private void setDoubleUnsafe(int slotIndex, FrameSlot slot, double value) {
+        long offset = getPrimitiveOffset(slotIndex);
         unsafePutDouble(getPrimitiveLocals(), offset, value, slot);
     }
 
@@ -243,65 +273,54 @@
         return this.descriptor;
     }
 
-    private void verifySet(FrameSlot slot, FrameSlotKind accessKind) {
-        int slotIndex = slot.getIndex();
-        if (slotIndex >= getTags().length) {
-            CompilerDirectives.transferToInterpreter();
+    private void verifySet(int slotIndex, byte tag) {
+        if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) {
             if (!resize()) {
-                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slotIndex));
             }
         }
-        getTags()[slotIndex] = (byte) accessKind.ordinal();
+        getTags()[slotIndex] = tag;
     }
 
-    private void verifyGet(FrameSlot slot, FrameSlotKind accessKind) throws FrameSlotTypeException {
-        int slotIndex = slot.getIndex();
-        if (slotIndex >= getTags().length) {
-            CompilerDirectives.transferToInterpreter();
+    private void verifyGet(int slotIndex, byte tag) throws FrameSlotTypeException {
+        if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) {
             if (!resize()) {
-                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slot));
+                throw new IllegalArgumentException(String.format("The frame slot '%s' is not known by the frame descriptor.", slotIndex));
             }
         }
-        byte tag = this.getTags()[slotIndex];
-        if (tag != accessKind.ordinal()) {
+        if (getTags()[slotIndex] != tag) {
             CompilerDirectives.transferToInterpreter();
             throw new FrameSlotTypeException();
         }
     }
 
-    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(int slotIndex) {
+        return Unsafe.ARRAY_LONG_BASE_OFFSET + slotIndex * (long) Unsafe.ARRAY_LONG_INDEX_SCALE;
     }
 
     @Override
     public Object getValue(FrameSlot slot) {
         int slotIndex = slot.getIndex();
-        if (slotIndex >= getTags().length) {
+        if (CompilerDirectives.inInterpreter() && slotIndex >= getTags().length) {
             CompilerDirectives.transferToInterpreter();
             resize();
         }
         byte tag = getTags()[slotIndex];
-        if (tag == FrameSlotKind.Boolean.ordinal()) {
-            return getBooleanUnsafe(slot);
-        } else if (tag == FrameSlotKind.Byte.ordinal()) {
-            return getByteUnsafe(slot);
-        } else if (tag == FrameSlotKind.Int.ordinal()) {
-            return getIntUnsafe(slot);
-        } else if (tag == FrameSlotKind.Double.ordinal()) {
-            return getDoubleUnsafe(slot);
-        } else if (tag == FrameSlotKind.Long.ordinal()) {
-            return getLongUnsafe(slot);
-        } else if (tag == FrameSlotKind.Float.ordinal()) {
-            return getFloatUnsafe(slot);
+        if (tag == FrameSlotKind.Boolean.tag) {
+            return getBooleanUnsafe(slotIndex, slot);
+        } else if (tag == FrameSlotKind.Byte.tag) {
+            return getByteUnsafe(slotIndex, slot);
+        } else if (tag == FrameSlotKind.Int.tag) {
+            return getIntUnsafe(slotIndex, slot);
+        } else if (tag == FrameSlotKind.Double.tag) {
+            return getDoubleUnsafe(slotIndex, slot);
+        } else if (tag == FrameSlotKind.Long.tag) {
+            return getLongUnsafe(slotIndex, slot);
+        } else if (tag == FrameSlotKind.Float.tag) {
+            return getFloatUnsafe(slotIndex, slot);
         } else {
-            assert tag == FrameSlotKind.Object.ordinal();
-            return getObjectUnsafe(slot);
+            assert tag == FrameSlotKind.Object.tag;
+            return getObjectUnsafe(slotIndex, slot);
         }
     }
 
@@ -329,37 +348,37 @@
 
     @Override
     public boolean isObject(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Object.ordinal();
+        return getTag(slot) == FrameSlotKind.Object.tag;
     }
 
     @Override
     public boolean isByte(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Byte.ordinal();
+        return getTag(slot) == FrameSlotKind.Byte.tag;
     }
 
     @Override
     public boolean isBoolean(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Boolean.ordinal();
+        return getTag(slot) == FrameSlotKind.Boolean.tag;
     }
 
     @Override
     public boolean isInt(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Int.ordinal();
+        return getTag(slot) == FrameSlotKind.Int.tag;
     }
 
     @Override
     public boolean isLong(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Long.ordinal();
+        return getTag(slot) == FrameSlotKind.Long.tag;
     }
 
     @Override
     public boolean isFloat(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Float.ordinal();
+        return getTag(slot) == FrameSlotKind.Float.tag;
     }
 
     @Override
     public boolean isDouble(FrameSlot slot) {
-        return getTag(slot) == FrameSlotKind.Double.ordinal();
+        return getTag(slot) == FrameSlotKind.Double.tag;
     }
 
     @SuppressWarnings({"unchecked", "unused"})
@@ -368,16 +387,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 +412,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Sat Feb 21 19:55:33 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 {
 
@@ -111,7 +113,11 @@
 
     @Override
     public MaterializedFrame createMaterializedFrame(Object[] arguments, FrameDescriptor frameDescriptor) {
-        return new FrameWithoutBoxing(frameDescriptor, arguments);
+        if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
+            return new FrameWithoutBoxing(frameDescriptor, arguments);
+        } else {
+            return new FrameWithBoxing(frameDescriptor, arguments);
+        }
     }
 
     @Override
@@ -181,6 +187,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/OptimizedAssumption.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedAssumption.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,6 +30,7 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.debug.*;
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.*;
 import com.oracle.truffle.api.impl.*;
 import com.oracle.truffle.api.nodes.*;
@@ -50,7 +51,8 @@
 
     @Override
     public void check() throws InvalidAssumptionException {
-        if (!isValid) {
+        if (!this.isValid()) {
+            CompilerDirectives.transferToInterpreterAndInvalidate();
             throw new InvalidAssumptionException();
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Sat Feb 21 19:55:33 2015 +0100
@@ -417,8 +417,12 @@
         return args;
     }
 
-    public static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, Object[] args) {
-        return new FrameWithoutBoxing(descriptor, args);
+    public static VirtualFrame createFrame(FrameDescriptor descriptor, Object[] args) {
+        if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
+            return new FrameWithoutBoxing(descriptor, args);
+        } else {
+            return new FrameWithBoxing(descriptor, args);
+        }
     }
 
     public List<OptimizedDirectCallNode> getCallNodes() {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
 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.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
@@ -38,9 +38,12 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.Node;
 import com.oracle.graal.java.*;
+import com.oracle.graal.java.GraphBuilderPlugin.LoadFieldPlugin;
+import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 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 +100,7 @@
         }
     }
 
-    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, final Assumptions assumptions) {
+    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions) {
         if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) {
             constantReceivers = new HashSet<>();
         }
@@ -108,7 +111,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 +120,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);
             } else {
                 createRootGraph(graph);
-                partialEvaluation(callTarget, assumptions, graph, baseContext, tierContext);
+                partialEvaluation(callTarget, graph, baseContext, tierContext);
             }
 
             if (Thread.currentThread().isInterrupted()) {
@@ -144,22 +147,12 @@
         return graph;
     }
 
-    private class InterceptLoadFieldPlugin implements GraphBuilderPlugins.LoadFieldPlugin {
+    private class InterceptLoadFieldPlugin implements LoadFieldPlugin {
 
         public boolean apply(GraphBuilderContext builder, ValueNode receiver, ResolvedJavaField field) {
             if (receiver.isConstant()) {
                 JavaConstant asJavaConstant = receiver.asJavaConstant();
-                return tryConstantFold(builder, field, asJavaConstant);
-            }
-            return false;
-        }
-
-        private boolean tryConstantFold(GraphBuilderContext builder, ResolvedJavaField field, JavaConstant asJavaConstant) {
-            JavaConstant result = providers.getConstantReflection().readConstantFieldValue(field, asJavaConstant);
-            if (result != null) {
-                ConstantNode constantNode = builder.append(ConstantNode.forConstant(result, providers.getMetaAccess()));
-                builder.push(constantNode.getKind().getStackKind(), constantNode);
-                return true;
+                return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), field, asJavaConstant);
             }
             return false;
         }
@@ -170,11 +163,11 @@
                 builder.push(trueNode.getKind().getStackKind(), trueNode);
                 return true;
             }
-            return tryConstantFold(builder, staticField, null);
+            return tryConstantFold(builder, providers.getMetaAccess(), providers.getConstantReflection(), staticField, null);
         }
     }
 
-    private class InterceptReceiverPlugin implements GraphBuilderPlugins.ParameterPlugin {
+    private class InterceptReceiverPlugin implements ParameterPlugin {
 
         private final Object receiver;
 
@@ -190,15 +183,56 @@
         }
     }
 
-    private class InlineInvokePlugin implements GraphBuilderPlugins.InlineInvokePlugin {
+    private class InlineInvokePlugin implements GraphBuilderPlugin.InlineInvokePlugin {
 
-        public boolean shouldInlineInvoke(ResolvedJavaMethod method, int depth) {
-            return method.getAnnotation(TruffleBoundary.class) == null;
+        private Stack<TruffleInlining> inlining;
+        private OptimizedDirectCallNode lastDirectCallNode;
+        private final Replacements replacements;
+
+        public InlineInvokePlugin(TruffleInlining inlining, Replacements replacements) {
+            this.inlining = new Stack<>();
+            this.inlining.push(inlining);
+            this.replacements = replacements;
         }
 
+        public ResolvedJavaMethod getInlinedMethod(GraphBuilderContext builder, ResolvedJavaMethod original, ValueNode[] arguments, JavaType returnType, int depth) {
+            if (original.getAnnotation(TruffleBoundary.class) != null) {
+                return null;
+            }
+            if (replacements != null && (replacements.getMethodSubstitutionMethod(original) != null || replacements.getMacroSubstitution(original) != null)) {
+                return null;
+            }
+            if (original.equals(callSiteProxyMethod)) {
+                ValueNode arg1 = arguments[0];
+                if (!arg1.isConstant()) {
+                    GraalInternalError.shouldNotReachHere("The direct call node does not resolve to a constant!");
+                }
+
+                Object callNode = builder.getSnippetReflection().asObject(Object.class, (JavaConstant) arg1.asConstant());
+                if (callNode instanceof OptimizedDirectCallNode) {
+                    OptimizedDirectCallNode directCallNode = (OptimizedDirectCallNode) callNode;
+                    lastDirectCallNode = directCallNode;
+                }
+            } else if (original.equals(callDirectMethod)) {
+                TruffleInliningDecision decision = getDecision(inlining.peek(), lastDirectCallNode);
+                lastDirectCallNode = null;
+                if (decision != null && decision.isInline()) {
+                    inlining.push(decision);
+                    builder.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) decision.getTarget().getNodeRewritingAssumption()));
+                    return callInlinedMethod;
+                }
+            }
+            return original;
+        }
+
+        public void postInline(ResolvedJavaMethod inlinedTargetMethod) {
+            if (inlinedTargetMethod.equals(callInlinedMethod)) {
+                inlining.pop();
+            }
+        }
     }
 
-    private class LoopExplosionPlugin implements GraphBuilderPlugins.LoopExplosionPlugin {
+    private class LoopExplosionPlugin implements GraphBuilderPlugin.LoopExplosionPlugin {
 
         public boolean shouldExplodeLoops(ResolvedJavaMethod method) {
             return method.getAnnotation(ExplodeLoop.class) != null;
@@ -207,21 +241,32 @@
     }
 
     @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) {
         GraphBuilderConfiguration newConfig = configForRoot.copy();
+        newConfig.setUseProfiling(false);
         newConfig.setLoadFieldPlugin(new InterceptLoadFieldPlugin());
         newConfig.setParameterPlugin(new InterceptReceiverPlugin(callTarget));
-        newConfig.setInlineInvokePlugin(new InlineInvokePlugin());
+        callTarget.setInlining(new TruffleInlining(callTarget, new DefaultInliningPolicy()));
+        newConfig.setInlineInvokePlugin(new InlineInvokePlugin(callTarget.getInlining(), providers.getReplacements()));
         newConfig.setLoopExplosionPlugin(new LoopExplosionPlugin());
-        DefaultGraphBuilderPlugins plugins = new DefaultGraphBuilderPlugins();
-        Iterable<GraphBuilderPluginsProvider> sl = Services.load(GraphBuilderPluginsProvider.class);
-        for (GraphBuilderPluginsProvider p : sl) {
-            p.registerPlugins(providers.getMetaAccess(), plugins);
+        TruffleGraphBuilderPlugins.registerInvocationPlugins(providers.getMetaAccess(), newConfig.getInvocationPlugins());
+        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig, TruffleCompilerImpl.Optimizations).apply(graph);
+        Debug.dump(graph, "After FastPE");
+
+        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE)) {
+            Class<? extends FixedWithNextNode> macroSubstitution = providers.getReplacements().getMacroSubstitution(methodCallTargetNode.targetMethod());
+            if (macroSubstitution != null) {
+                InliningUtil.inlineMacroNode(methodCallTargetNode.invoke(), methodCallTargetNode.targetMethod(), macroSubstitution);
+            } else {
+                StructuredGraph inlineGraph = providers.getReplacements().getMethodSubstitution(methodCallTargetNode.targetMethod());
+                if (inlineGraph != null) {
+                    InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, true, null);
+                }
+            }
         }
-        TruffleGraphBuilderPlugins.registerPlugins(providers.getMetaAccess(), plugins);
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), new Assumptions(false), providers.getConstantReflection(), newConfig, plugins,
-                        TruffleCompilerImpl.Optimizations).apply(graph);
-        Debug.dump(graph, "After FastPE");
+
+        // Perform dead code elimination. Dead nodes mainly come from parse time canonicalizations.
+        new DeadCodeEliminationPhase().apply(graph);
 
         // Do single partial escape and canonicalization pass.
         try (Scope pe = Debug.scope("TrufflePartialEscape", graph)) {
@@ -232,7 +277,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");
@@ -242,7 +287,7 @@
             expansionLogger = new TruffleExpansionLogger(providers, graph);
         }
 
-        expandTree(graph, assumptions, expansionLogger);
+        expandTree(graph, expansionLogger);
 
         TruffleInliningCache inliningCache = null;
         if (TruffleFunctionInlining.getValue()) {
@@ -252,7 +297,7 @@
             }
         }
 
-        expandDirectCalls(graph, assumptions, expansionLogger, callTarget.getInlining(), inliningCache);
+        expandDirectCalls(graph, expansionLogger, callTarget.getInlining(), inliningCache);
 
         if (Thread.currentThread().isInterrupted()) {
             return;
@@ -267,7 +312,7 @@
             } catch (Throwable t) {
                 Debug.handle(t);
             }
-        } while (expandTree(graph, assumptions, expansionLogger));
+        } while (expandTree(graph, expansionLogger));
 
         if (expansionLogger != null) {
             expansionLogger.print(callTarget);
@@ -275,25 +320,23 @@
     }
 
     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;
     }
 
     private static void postPartialEvaluation(final StructuredGraph graph) {
         NeverPartOfCompilationNode.verifyNotFoundIn(graph);
-        for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.class).snapshot()) {
+        for (MaterializeFrameNode materializeNode : graph.getNodes(MaterializeFrameNode.TYPE).snapshot()) {
             materializeNode.replaceAtUsages(materializeNode.getFrame());
             graph.removeFixed(materializeNode);
         }
-        for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.class)) {
+        for (VirtualObjectNode virtualObjectNode : graph.getNodes(VirtualObjectNode.TYPE)) {
             if (virtualObjectNode instanceof VirtualOnlyInstanceNode) {
                 VirtualOnlyInstanceNode virtualOnlyInstanceNode = (VirtualOnlyInstanceNode) virtualObjectNode;
                 virtualOnlyInstanceNode.setAllowMaterialization(true);
@@ -339,8 +382,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<>();
@@ -437,7 +480,7 @@
             assert graph.hasLoops() : graph + " does not contain a loop";
             final StructuredGraph graphCopy = graph.copy();
             final List<Node> modifiedNodes = new ArrayList<>();
-            for (ParameterNode param : graphCopy.getNodes(ParameterNode.class).snapshot()) {
+            for (ParameterNode param : graphCopy.getNodes(ParameterNode.TYPE).snapshot()) {
                 ValueNode arg = arguments.get(param.index());
                 if (arg.isConstant()) {
                     Constant constant = arg.asConstant();
@@ -481,23 +524,23 @@
         }
     }
 
-    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);
+        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE).snapshot()) {
+            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);
     }
 
     private boolean noDirectCallsLeft(StructuredGraph graph) {
-        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
+        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE).snapshot()) {
             if (methodCallTargetNode.targetMethod().equals(callDirectMethod)) {
                 return false;
             }
@@ -505,13 +548,32 @@
         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) {
             return null;
         }
 
+        TruffleInliningDecision decision = getDecision(inlining, callNode);
+
+        StructuredGraph graph;
+        if (decision != null && decision.isInline()) {
+            if (inliningCache == null) {
+                graph = createInlineGraph(phaseContext, caller, null, decision);
+            } else {
+                graph = inliningCache.getCachedGraph(phaseContext, caller, decision);
+            }
+            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);
+        }
+
+        return graph;
+    }
+
+    private static TruffleInliningDecision getDecision(TruffleInlining inlining, OptimizedDirectCallNode callNode) {
         TruffleInliningDecision decision = inlining.findByCall(callNode);
         if (decision == null) {
             if (TruffleCompilerOptions.TraceTrufflePerformanceWarnings.getValue()) {
@@ -528,25 +590,9 @@
                 properties.put("callNode", callNode);
                 TracePerformanceWarningsListener.logPerformanceWarning(String.format("CallTarget changed during compilation. Call node could not be inlined."), properties);
             }
-            decision = null;
+            return null;
         }
-
-        StructuredGraph graph;
-        if (decision != null && decision.isInline()) {
-            if (inliningCache == null) {
-                graph = createInlineGraph(phaseContext, assumptions, null, decision);
-            } else {
-                graph = inliningCache.getCachedGraph(phaseContext, assumptions, decision);
-            }
-            decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount());
-
-            assumptions.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);
-        }
-
-        return graph;
+        return decision;
     }
 
     private OptimizedDirectCallNode resolveConstantCallNode(MethodCallTargetNode methodCallTargetNode) {
@@ -589,17 +635,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);
@@ -630,11 +676,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Sat Feb 21 19:55:33 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;
             }
@@ -136,7 +136,7 @@
             lastUsed.put(key, counter++);
             cache.put(key, markerGraph);
 
-            for (ParameterNode param : graph.getNodes(ParameterNode.class)) {
+            for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
                 if (param.getKind() == Kind.Object) {
                     ValueNode actualArgument = arguments.get(param.index());
                     param.setStamp(param.stamp().join(actualArgument.stamp()));
@@ -164,7 +164,7 @@
                 canonicalizer.apply(graph, phaseContext);
 
                 boolean inliningProgress = false;
-                for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
+                for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
                     if (!graph.getMark().equals(mark)) {
                         mark = lookupProcessMacroSubstitutions(graph, mark);
                     }
@@ -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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Sat Feb 21 19:55:33 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.*;
@@ -40,7 +40,9 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.java.*;
 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.*;
@@ -59,6 +61,7 @@
 
     private final Providers providers;
     private final Suites suites;
+    private final LIRSuites lirSuites;
     private final PartialEvaluator partialEvaluator;
     private final Backend backend;
     private final GraphBuilderConfiguration config;
@@ -66,7 +69,8 @@
     private final TruffleCache truffleCache;
     private final GraalTruffleCompilationListener compilationNotify;
 
-    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class};
+    private static final Class<?>[] SKIPPED_EXCEPTION_CLASSES = new Class[]{UnexpectedResultException.class, SlowPathException.class, ArithmeticException.class, IllegalArgumentException.class,
+                    VirtualMachineError.class, ClassCastException.class};
 
     public static final OptimisticOptimizations Optimizations = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseExceptionProbability,
                     OptimisticOptimizations.Optimization.RemoveNeverExecutedCode, OptimisticOptimizations.Optimization.UseTypeCheckedInlining, OptimisticOptimizations.Optimization.UseTypeCheckHints);
@@ -77,13 +81,24 @@
         this.compilationNotify = graalTruffleRuntime.getCompilationNotify();
         this.backend = runtime.getHostBackend();
         Replacements truffleReplacements = graalTruffleRuntime.getReplacements();
-        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backend.getProviders().getConstantReflection(), backend.getProviders().getMetaAccess());
-        this.providers = backend.getProviders().copyWith(truffleReplacements).copyWith(constantReflection);
+        Providers backendProviders = backend.getProviders();
+        ConstantReflectionProvider constantReflection = new TruffleConstantReflectionProvider(backendProviders.getConstantReflection(), backendProviders.getMetaAccess());
+        if (!TruffleCompilerOptions.FastPE.getValue()) {
+            backendProviders = backendProviders.copyWith(truffleReplacements);
+        }
+        this.providers = backendProviders.copyWith(constantReflection);
         this.suites = backend.getSuites().getDefaultSuites();
+        this.lirSuites = backend.getSuites().getDefaultLIRSuites();
 
         ResolvedJavaType[] skippedExceptionTypes = getSkippedExceptionTypes(providers.getMetaAccess());
         GraphBuilderConfiguration eagerConfig = GraphBuilderConfiguration.getEagerDefault().withSkippedExceptionTypes(skippedExceptionTypes);
+
         this.config = GraphBuilderConfiguration.getDefault().withSkippedExceptionTypes(skippedExceptionTypes);
+        if (TruffleCompilerOptions.FastPE.getValue()) {
+            GraphBuilderPhase phase = (GraphBuilderPhase) backend.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
+            this.config.getInvocationPlugins().setDefaults(phase.getGraphBuilderConfig().getInvocationPlugins());
+        }
+
         this.truffleCache = new TruffleCacheImpl(providers, eagerConfig, TruffleCompilerImpl.Optimizations);
 
         this.partialEvaluator = new PartialEvaluator(providers, config, truffleCache, Graal.getRequiredCapability(SnippetReflectionProvider.class));
@@ -115,10 +130,10 @@
         compilationNotify.notifyCompilationStarted(compilable);
 
         try {
-            Assumptions assumptions = new Assumptions(true);
+            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
 
             try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
-                graph = partialEvaluator.createGraph(compilable, assumptions);
+                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
             }
 
             if (Thread.currentThread().isInterrupted()) {
@@ -127,21 +142,22 @@
 
             if (!TruffleCompilerOptions.TruffleInlineAcrossTruffleBoundary.getValue()) {
                 // Do not inline across Truffle boundaries.
-                for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.class)) {
+                for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.TYPE)) {
                     mct.invoke().setUseForInlining(false);
                 }
             }
 
             compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
-            CompilationResult compilationResult = compileMethodHelper(graph, assumptions, compilable.toString(), compilable.getSpeculationLog(), compilable);
+            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), graphBuilderSuite, compilable.getSpeculationLog(), compilable);
             compilationNotify.notifyCompilationSuccess(compilable, graph, compilationResult);
         } catch (Throwable t) {
+            System.out.println("compilation failed!?");
             compilationNotify.notifyCompilationFailed(compilable, graph, t);
             throw t;
         }
     }
 
-    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) {
@@ -153,29 +169,33 @@
             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, compilationResult, CompilationResultBuilderFactory.Default);
+            result = compileGraph(graph, cc, graph.method(), providers, backend, codeCache.getTarget(), null, graphBuilderSuite, Optimizations, getProfilingInfo(graph), speculationLog, suites,
+                            lirSuites, compilationResult, CompilationResultBuilderFactory.Default);
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
 
         compilationNotify.notifyCompilationGraalTierFinished((OptimizedCallTarget) predefinedInstalledCode, graph);
 
+        if (graph.isInlinedMethodRecordingEnabled()) {
+            result.setMethods(graph.method(), graph.getInlinedMethods());
+        } 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()) {
@@ -197,19 +217,18 @@
     private PhaseSuite<HighTierContext> 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()));
+        iterator.add(new GraphBuilderPhase(config));
         return suite;
     }
 
-    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/TruffleCompilerOptions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -104,6 +104,9 @@
     @Option(help = "Enable asynchronous truffle compilation in background thread", type = OptionType.Expert)
     public static final OptionValue<Boolean> TruffleBackgroundCompilation = new OptionValue<>(true);
 
+    @Option(help = "Manually set the number of compiler threads", type = OptionType.Expert)
+    public static final StableOptionValue<Integer> TruffleCompilerThreads = new StableOptionValue<>(0);
+
     @Option(help = "Enable inlining across Truffle boundary", type = OptionType.Expert)
     public static final OptionValue<Boolean> TruffleInlineAcrossTruffleBoundary = new OptionValue<>(false);
 
@@ -119,6 +122,9 @@
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> TruffleArgumentTypeSpeculation = new StableOptionValue<>(true);
 
+    @Option(help = "", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> TruffleUseFrameWithoutBoxing = new StableOptionValue<>(true);
+
     // tracing
     @Option(help = "Print potential performance problems", type = OptionType.Debug)
     public static final OptionValue<Boolean> TraceTrufflePerformanceWarnings = new OptionValue<>(false);
@@ -181,6 +187,6 @@
     public static final OptionValue<Boolean> TruffleCompilationStatisticDetails = new OptionValue<>(false);
 
     @Option(help = "Experimental new version of the partial evaluator.", type = OptionType.Debug)
-    public static final OptionValue<Boolean> FastPE = new OptionValue<>(false);
+    public static final OptionValue<Boolean> FastPE = new OptionValue<>(true);
     // @formatter:on
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Sat Feb 21 19:55:33 2015 +0100
@@ -84,7 +84,7 @@
     }
 
     private void registerParentInCalls(ExpansionTree parentTree, StructuredGraph graph) {
-        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.TYPE)) {
             callToParentTree.put(target, parentTree);
         }
     }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,7 +32,6 @@
     private final double frequency;
     private final boolean recursiveCall;
 
-    private int graalDeepNodeCount = -1;
     private String failedReason;
     private int queryIndex = -1;
     private double score;
@@ -103,19 +102,7 @@
         properties.put("frequency", String.format("%8.4f", getFrequency()));
         properties.put("score", String.format("%8.4f", getScore()));
         properties.put(String.format("index=%3d, force=%s, callSites=%2d", queryIndex, (isForced() ? "Y" : "N"), getCallSites()), "");
-        if (graalDeepNodeCount != -1) {
-            properties.put("graalCount", String.format("%5d", graalDeepNodeCount));
-        }
         properties.put("reason", failedReason);
         return properties;
     }
-
-    public void setGraalDeepNodeCount(int graalDeepNodeCount) {
-        this.graalDeepNodeCount = graalDeepNodeCount;
-    }
-
-    public int getGraalDeepNodeCount() {
-        return graalDeepNodeCount;
-    }
-
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Sat Feb 21 19:55:33 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,19 +43,22 @@
     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();
     }
 
     protected void registerTruffleSubstitutions() {
-        registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
-        registerSubstitutions(CompilerDirectives.class, CompilerDirectivesSubstitutions.class);
-        registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
-        registerSubstitutions(OptimizedAssumption.class, OptimizedAssumptionSubstitutions.class);
-        registerSubstitutions(OptimizedCallTarget.class, OptimizedCallTargetSubstitutions.class);
-        registerSubstitutions(FrameWithoutBoxing.class, FrameWithoutBoxingSubstitutions.class);
+        if (!TruffleCompilerOptions.FastPE.getValue()) {
+            registerSubstitutions(CompilerAsserts.class, CompilerAssertsSubstitutions.class);
+            registerSubstitutions(CompilerDirectives.class, CompilerDirectivesSubstitutions.class);
+            registerSubstitutions(ExactMath.class, ExactMathSubstitutions.class);
+            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/debug/TraceCompilationFailureListener.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationFailureListener.java	Sat Feb 21 19:55:33 2015 +0100
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.graal.api.code.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.truffle.*;
 
@@ -39,7 +40,7 @@
 
     @Override
     public void notifyCompilationFailed(OptimizedCallTarget target, StructuredGraph graph, Throwable t) {
-        if (isPermanentBailout(t)) {
+        if (isPermanentBailout(t) || GraalOptions.PrintBailout.getValue()) {
             Map<String, Object> properties = new LinkedHashMap<>();
             properties.put("Reason", t.toString());
             log(0, "opt fail", target.toString(), properties);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,10 +22,12 @@
  */
 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.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -37,8 +39,10 @@
 @NodeInfo
 public final class AssumptionNode extends MacroNode implements Simplifiable {
 
+    public static final NodeClass<AssumptionNode> TYPE = NodeClass.create(AssumptionNode.class);
+
     public AssumptionNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
         assert super.arguments.size() == 1;
     }
 
@@ -62,14 +66,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/BailoutNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,8 +33,10 @@
 @NodeInfo
 public final class BailoutNode extends MacroNode implements Canonicalizable {
 
+    public static final NodeClass<BailoutNode> TYPE = NodeClass.create(BailoutNode.class);
+
     public BailoutNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
         assert arguments.size() == 1;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/IsCompilationConstantNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/IsCompilationConstantNode.java	Sat Feb 21 19:55:33 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
@@ -22,31 +22,36 @@
  */
 package com.oracle.graal.truffle.nodes;
 
+import com.oracle.graal.api.meta.*;
+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.replacements.nodes.*;
 
 @NodeInfo
-public class IsCompilationConstantNode extends MacroStateSplitNode implements Canonicalizable {
+public final class IsCompilationConstantNode extends FloatingNode implements Lowerable, Canonicalizable {
+
+    public static final NodeClass<IsCompilationConstantNode> TYPE = NodeClass.create(IsCompilationConstantNode.class);
 
-    public IsCompilationConstantNode(Invoke invoke) {
-        super(invoke);
-        assert arguments.size() == 1;
+    @Input ValueNode value;
+
+    public IsCompilationConstantNode(ValueNode value) {
+        super(TYPE, StampFactory.forKind(Kind.Boolean));
+        this.value = value;
     }
 
     @Override
     public void lower(LoweringTool tool) {
-        /* Invoke will return false. */
-        replaceWithInvoke().lower(tool);
+        graph().replaceFloating(this, ConstantNode.forBoolean(false, graph()));
     }
 
     @Override
     public Node canonical(CanonicalizerTool tool) {
-        ValueNode arg0 = arguments.get(0);
+        ValueNode arg0 = value;
         if (arg0 instanceof BoxNode) {
             arg0 = ((BoxNode) arg0).getValue();
         }
@@ -55,4 +60,7 @@
         }
         return this;
     }
+
+    @NodeIntrinsic
+    public static native boolean check(Object value);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -36,10 +37,11 @@
  * case the addition would overflow the 32 bit range.
  */
 @NodeInfo
-public class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode {
+public final class IntegerAddExactNode extends AddNode implements IntegerExactArithmeticNode {
+    public static final NodeClass<IntegerAddExactNode> TYPE = NodeClass.create(IntegerAddExactNode.class);
 
     public IntegerAddExactNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(TYPE, x, y);
         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java	Sat Feb 21 19:55:33 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
@@ -24,15 +24,17 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class IntegerAddExactSplitNode extends IntegerExactArithmeticSplitNode {
+public final class IntegerAddExactSplitNode extends IntegerExactArithmeticSplitNode {
+    public static final NodeClass<IntegerAddExactSplitNode> TYPE = NodeClass.create(IntegerAddExactSplitNode.class);
 
     public IntegerAddExactSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
-        super(stamp, x, y, next, overflowSuccessor);
+        super(TYPE, stamp, x, y, next, overflowSuccessor);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Sat Feb 21 19:55:33 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
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -31,14 +32,15 @@
 
 @NodeInfo
 public abstract class IntegerExactArithmeticSplitNode extends ControlSplitNode implements LIRLowerable {
+    public static final NodeClass<IntegerExactArithmeticSplitNode> TYPE = NodeClass.create(IntegerExactArithmeticSplitNode.class);
 
     @Successor AbstractBeginNode overflowSuccessor;
     @Successor AbstractBeginNode next;
     @Input ValueNode x;
     @Input ValueNode y;
 
-    public IntegerExactArithmeticSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
-        super(stamp);
+    protected IntegerExactArithmeticSplitNode(NodeClass<? extends IntegerExactArithmeticSplitNode> c, Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
+        super(c, stamp);
         this.x = x;
         this.y = y;
         this.overflowSuccessor = overflowSuccessor;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -36,10 +37,11 @@
  * in case the addition would overflow the 32 bit range.
  */
 @NodeInfo
-public class IntegerMulExactNode extends MulNode implements IntegerExactArithmeticNode {
+public final class IntegerMulExactNode extends MulNode implements IntegerExactArithmeticNode {
+    public static final NodeClass<IntegerMulExactNode> TYPE = NodeClass.create(IntegerMulExactNode.class);
 
     public IntegerMulExactNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(TYPE, x, y);
         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java	Sat Feb 21 19:55:33 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
@@ -24,15 +24,17 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class IntegerMulExactSplitNode extends IntegerExactArithmeticSplitNode {
+public final class IntegerMulExactSplitNode extends IntegerExactArithmeticSplitNode {
+    public static final NodeClass<IntegerMulExactSplitNode> TYPE = NodeClass.create(IntegerMulExactSplitNode.class);
 
     public IntegerMulExactSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
-        super(stamp, x, y, next, overflowSuccessor);
+        super(TYPE, stamp, x, y, next, overflowSuccessor);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Sat Feb 21 19:55:33 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
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,14 +36,15 @@
 import com.oracle.truffle.api.*;
 
 @NodeInfo(shortName = "*H")
-public class IntegerMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+public final class IntegerMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+    public static final NodeClass<IntegerMulHighNode> TYPE = NodeClass.create(IntegerMulHighNode.class);
 
     public IntegerMulHighNode(ValueNode x, ValueNode y) {
         this((IntegerStamp) x.stamp().unrestricted(), x, y);
     }
 
     public IntegerMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+        super(TYPE, stamp, x, y);
     }
 
     /**
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.api.meta.*;
 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.*;
@@ -37,10 +38,11 @@
  * case the addition would overflow the 32 bit range.
  */
 @NodeInfo
-public class IntegerSubExactNode extends SubNode implements IntegerExactArithmeticNode {
+public final class IntegerSubExactNode extends SubNode implements IntegerExactArithmeticNode {
+    public static final NodeClass<IntegerSubExactNode> TYPE = NodeClass.create(IntegerSubExactNode.class);
 
     public IntegerSubExactNode(ValueNode x, ValueNode y) {
-        super(x, y);
+        super(TYPE, x, y);
         assert x.stamp().isCompatible(y.stamp()) && x.stamp() instanceof IntegerStamp;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java	Sat Feb 21 19:55:33 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
@@ -24,15 +24,17 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class IntegerSubExactSplitNode extends IntegerExactArithmeticSplitNode {
+public final class IntegerSubExactSplitNode extends IntegerExactArithmeticSplitNode {
+    public static final NodeClass<IntegerSubExactSplitNode> TYPE = NodeClass.create(IntegerSubExactSplitNode.class);
 
     public IntegerSubExactSplitNode(Stamp stamp, ValueNode x, ValueNode y, AbstractBeginNode next, AbstractBeginNode overflowSuccessor) {
-        super(stamp, x, y, next, overflowSuccessor);
+        super(TYPE, stamp, x, y, next, overflowSuccessor);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Sat Feb 21 19:55:33 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
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -35,14 +36,16 @@
 import com.oracle.truffle.api.*;
 
 @NodeInfo(shortName = "|*H|")
-public class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+public final class UnsignedMulHighNode extends BinaryNode implements ArithmeticLIRLowerable {
+
+    public static final NodeClass<UnsignedMulHighNode> TYPE = NodeClass.create(UnsignedMulHighNode.class);
 
     public UnsignedMulHighNode(ValueNode x, ValueNode y) {
         this((IntegerStamp) x.stamp().unrestricted(), x, y);
     }
 
     public UnsignedMulHighNode(IntegerStamp stamp, ValueNode x, ValueNode y) {
-        super(stamp, x, y);
+        super(TYPE, stamp, x, y);
     }
 
     /**
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/CompilationConstantNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.truffle.nodes.asserts;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-
-@NodeInfo
-public final class CompilationConstantNode extends NeverPartOfCompilationNode implements Canonicalizable {
-
-    public CompilationConstantNode(Invoke invoke) {
-        super(invoke, "The value could not be reduced to a compile time constant.");
-        assert arguments.size() == 1;
-    }
-
-    @Override
-    public Node canonical(CanonicalizerTool tool) {
-        if (arguments.get(0).isConstant()) {
-            return arguments.get(0);
-        }
-        return this;
-    }
-}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Sat Feb 21 19:55:33 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
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.truffle.nodes.asserts;
 
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
@@ -30,8 +31,10 @@
 @NodeInfo
 public final class NeverInlineMacroNode extends MacroStateSplitNode implements com.oracle.graal.graph.IterableNodeType {
 
+    public static final NodeClass<NeverInlineMacroNode> TYPE = NodeClass.create(NeverInlineMacroNode.class);
+
     public NeverInlineMacroNode(Invoke invoke) {
-        super(invoke);
+        super(TYPE, invoke);
     }
 
     @Override
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,34 +22,34 @@
  */
 package com.oracle.graal.truffle.nodes.asserts;
 
+import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.replacements.nodes.*;
 
 @NodeInfo
-public class NeverPartOfCompilationNode extends MacroStateSplitNode implements IterableNodeType {
+public final class NeverPartOfCompilationNode extends FixedWithNextNode implements IterableNodeType {
 
+    public static final NodeClass<NeverPartOfCompilationNode> TYPE = NodeClass.create(NeverPartOfCompilationNode.class);
     protected final String message;
 
-    public NeverPartOfCompilationNode(Invoke invoke) {
-        this(invoke, "This code path should never be part of a compilation.");
-    }
-
-    public NeverPartOfCompilationNode(Invoke invoke, String message) {
-        super(invoke);
+    public NeverPartOfCompilationNode(String message) {
+        super(TYPE, StampFactory.forVoid());
         this.message = message;
     }
 
-    public final String getMessage() {
-        return message + " " + arguments.toString();
+    public String getMessage() {
+        return message;
     }
 
     public static void verifyNotFoundIn(final StructuredGraph graph) {
-        for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.class)) {
+        for (NeverPartOfCompilationNode neverPartOfCompilationNode : graph.getNodes(NeverPartOfCompilationNode.TYPE)) {
             Throwable exception = new VerificationError(neverPartOfCompilationNode.getMessage());
             throw GraphUtil.approxSourceException(neverPartOfCompilationNode, exception);
         }
     }
+
+    @NodeIntrinsic
+    public static native void apply(@ConstantNodeParameter String message);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,17 +23,19 @@
 package com.oracle.graal.truffle.nodes.frame;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable {
+public final class ForceMaterializeNode extends FixedWithNextNode implements LIRLowerable {
+    public static final NodeClass<ForceMaterializeNode> TYPE = NodeClass.create(ForceMaterializeNode.class);
 
     @Input ValueNode object;
 
     public ForceMaterializeNode(ValueNode object) {
-        super(StampFactory.forVoid());
+        super(TYPE, StampFactory.forVoid());
         this.object = object;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Sat Feb 21 19:55:33 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,18 +25,19 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.truffle.*;
+import com.oracle.truffle.api.frame.*;
 
 /**
  * Intrinsic node for materializing a Truffle frame.
  */
 @NodeInfo(nameTemplate = "MaterializeFrame{p#frame/s}")
-public class MaterializeFrameNode extends FixedWithNextNode implements IterableNodeType {
+public final class MaterializeFrameNode extends FixedWithNextNode implements IterableNodeType {
 
+    public static final NodeClass<MaterializeFrameNode> TYPE = NodeClass.create(MaterializeFrameNode.class);
     @Input ValueNode frame;
 
     public MaterializeFrameNode(ValueNode frame) {
-        super(frame.stamp());
+        super(TYPE, frame.stamp());
         this.frame = frame;
     }
 
@@ -45,5 +46,5 @@
     }
 
     @NodeIntrinsic
-    public static native <T> T materialize(FrameWithoutBoxing frame);
+    public static native <T> T materialize(VirtualFrame frame);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,11 +48,12 @@
 @NodeInfo
 public final class NewFrameNode extends FixedWithNextNode implements IterableNodeType, VirtualizableAllocation, Canonicalizable {
 
+    public static final NodeClass<NewFrameNode> TYPE = NodeClass.create(NewFrameNode.class);
     @Input ValueNode descriptor;
     @Input ValueNode arguments;
 
     public NewFrameNode(Stamp stamp, ValueNode descriptor, ValueNode arguments) {
-        super(stamp);
+        super(TYPE, stamp);
         this.descriptor = descriptor;
         this.arguments = arguments;
     }
@@ -92,16 +93,17 @@
                 return field;
             }
         }
-        throw new RuntimeException("Frame field not found: " + fieldName);
+        return null;
     }
 
     @NodeInfo
     public static final class VirtualOnlyInstanceNode extends VirtualInstanceNode {
 
+        public static final NodeClass<VirtualOnlyInstanceNode> TYPE = NodeClass.create(VirtualOnlyInstanceNode.class);
         protected boolean allowMaterialization;
 
         public VirtualOnlyInstanceNode(ResolvedJavaType type, ResolvedJavaField[] fields) {
-            super(type, fields, true);
+            super(TYPE, type, fields, true);
         }
 
         @Override
@@ -156,8 +158,8 @@
 
         VirtualObjectNode virtualFrame = new VirtualOnlyInstanceNode(frameType, frameFields);
         VirtualObjectNode virtualFrameObjectArray = new VirtualArrayNode((ResolvedJavaType) localsField.getType().getComponentType(), frameSize);
-        VirtualObjectNode virtualFramePrimitiveArray = new VirtualArrayNode((ResolvedJavaType) primitiveLocalsField.getType().getComponentType(), frameSize);
-        VirtualObjectNode virtualFrameTagArray = new VirtualArrayNode((ResolvedJavaType) tagsField.getType().getComponentType(), frameSize);
+        VirtualObjectNode virtualFramePrimitiveArray = (primitiveLocalsField == null ? null : new VirtualArrayNode((ResolvedJavaType) primitiveLocalsField.getType().getComponentType(), frameSize));
+        VirtualObjectNode virtualFrameTagArray = (primitiveLocalsField == null ? null : new VirtualArrayNode((ResolvedJavaType) tagsField.getType().getComponentType(), frameSize));
 
         ValueNode[] objectArrayEntryState = new ValueNode[frameSize];
         ValueNode[] primitiveArrayEntryState = new ValueNode[frameSize];
@@ -168,25 +170,37 @@
             ConstantNode objectDefault = ConstantNode.forConstant(getSnippetReflection().forObject(frameDescriptor.getDefaultValue()), tool.getMetaAccessProvider(), graph());
             ConstantNode tagDefault = ConstantNode.forByte((byte) 0, graph());
             Arrays.fill(objectArrayEntryState, objectDefault);
-            Arrays.fill(tagArrayEntryState, tagDefault);
-            for (int i = 0; i < frameSize; i++) {
-                primitiveArrayEntryState[i] = initialPrimitiveValue(frameDescriptor.getSlots().get(i).getKind());
+            if (virtualFrameTagArray != null) {
+                Arrays.fill(tagArrayEntryState, tagDefault);
             }
-            tool.getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
+            if (virtualFramePrimitiveArray != null) {
+                for (int i = 0; i < frameSize; i++) {
+                    primitiveArrayEntryState[i] = initialPrimitiveValue(frameDescriptor.getSlots().get(i).getKind());
+                }
+            }
+            graph().getAssumptions().record(new AssumptionValidAssumption((OptimizedAssumption) frameDescriptor.getVersion()));
         }
 
         tool.createVirtualObject(virtualFrameObjectArray, objectArrayEntryState, Collections.<MonitorIdNode> emptyList());
-        tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList());
-        tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        if (virtualFramePrimitiveArray != null) {
+            tool.createVirtualObject(virtualFramePrimitiveArray, primitiveArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        }
+        if (virtualFrameTagArray != null) {
+            tool.createVirtualObject(virtualFrameTagArray, tagArrayEntryState, Collections.<MonitorIdNode> emptyList());
+        }
 
-        assert frameFields.length == 5;
+        assert frameFields.length == 5 || frameFields.length == 3;
         ValueNode[] frameEntryState = new ValueNode[frameFields.length];
         List<ResolvedJavaField> frameFieldList = Arrays.asList(frameFields);
         frameEntryState[frameFieldList.indexOf(descriptorField)] = getDescriptor();
         frameEntryState[frameFieldList.indexOf(argumentsField)] = getArguments();
         frameEntryState[frameFieldList.indexOf(localsField)] = virtualFrameObjectArray;
-        frameEntryState[frameFieldList.indexOf(primitiveLocalsField)] = virtualFramePrimitiveArray;
-        frameEntryState[frameFieldList.indexOf(tagsField)] = virtualFrameTagArray;
+        if (primitiveLocalsField != null) {
+            frameEntryState[frameFieldList.indexOf(primitiveLocalsField)] = virtualFramePrimitiveArray;
+        }
+        if (tagsField != null) {
+            frameEntryState[frameFieldList.indexOf(tagsField)] = virtualFrameTagArray;
+        }
         tool.createVirtualObject(virtualFrame, frameEntryState, Collections.<MonitorIdNode> emptyList());
         tool.replaceWithVirtual(virtualFrame);
     }
@@ -195,11 +209,7 @@
         Kind graalKind = null;
         switch (kind) {
             case Boolean:
-                graalKind = Kind.Boolean;
-                break;
             case Byte:
-                graalKind = Kind.Byte;
-                break;
             case Int:
                 graalKind = Kind.Int;
                 break;
@@ -234,5 +244,5 @@
     }
 
     @NodeIntrinsic
-    public static native FrameWithoutBoxing allocate(@ConstantNodeParameter Class<? extends VirtualFrame> frameType, FrameDescriptor descriptor, Object[] args);
+    public static native VirtualFrame allocate(@ConstantNodeParameter Class<? extends VirtualFrame> frameType, FrameDescriptor descriptor, Object[] args);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadFinalNode.java	Sat Feb 21 19:47:33 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) {
-        CompareNode compare = CompareNode.createCompareNode(graph(), Condition.EQ, condition, ConstantNode.forBoolean(true, graph()));
-        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/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,14 +30,15 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.truffle.nodes.*;
-import com.oracle.graal.truffle.nodes.asserts.*;
 
 /**
  * Macro node for CompilerDirectives#unsafeGetInt*.
  */
 @NodeInfo
-public final class CustomizedUnsafeLoadMacroNode extends NeverPartOfCompilationNode implements Canonicalizable {
+public final class CustomizedUnsafeLoadMacroNode extends MacroStateSplitNode implements Canonicalizable {
+    public static final NodeClass<CustomizedUnsafeLoadMacroNode> TYPE = NodeClass.create(CustomizedUnsafeLoadMacroNode.class);
 
     private static final int ARGUMENT_COUNT = 4;
     private static final int OBJECT_ARGUMENT_INDEX = 0;
@@ -46,7 +47,7 @@
     private static final int LOCATION_ARGUMENT_INDEX = 3;
 
     public CustomizedUnsafeLoadMacroNode(Invoke invoke) {
-        super(invoke, "The location argument could not be resolved to a constant.");
+        super(TYPE, invoke);
         assert arguments.size() == ARGUMENT_COUNT;
     }
 
@@ -63,7 +64,7 @@
             } else {
                 locationIdentity = ObjectLocationIdentity.create(locationArgument.asJavaConstant());
             }
-            CompareNode compare = CompareNode.createCompareNode(Condition.EQ, conditionArgument, ConstantNode.forBoolean(true));
+            LogicNode compare = CompareNode.createCompareNode(Condition.EQ, conditionArgument, ConstantNode.forBoolean(true), tool.getConstantReflection());
             Kind returnKind = this.getTargetMethod().getSignature().getReturnKind();
             return new UnsafeLoadNode(objectArgument, offsetArgument, returnKind, locationIdentity, compare);
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,14 +28,15 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.truffle.nodes.*;
-import com.oracle.graal.truffle.nodes.asserts.*;
 
 /**
  * Macro node for method CompilerDirectives#unsafePut*.
  */
 @NodeInfo
-public final class CustomizedUnsafeStoreMacroNode extends NeverPartOfCompilationNode implements Canonicalizable, StateSplit {
+public final class CustomizedUnsafeStoreMacroNode extends MacroStateSplitNode implements Canonicalizable, StateSplit {
+    public static final NodeClass<CustomizedUnsafeStoreMacroNode> TYPE = NodeClass.create(CustomizedUnsafeStoreMacroNode.class);
     private static final int ARGUMENT_COUNT = 4;
     private static final int OBJECT_ARGUMENT_INDEX = 0;
     private static final int OFFSET_ARGUMENT_INDEX = 1;
@@ -43,7 +44,7 @@
     private static final int LOCATION_ARGUMENT_INDEX = 3;
 
     public CustomizedUnsafeStoreMacroNode(Invoke invoke) {
-        super(invoke, "The location argument could not be resolved to a constant.");
+        super(TYPE, invoke);
         assert arguments.size() == ARGUMENT_COUNT;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,19 +25,21 @@
 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.util.*;
-import com.oracle.graal.truffle.nodes.asserts.*;
+import com.oracle.graal.replacements.nodes.*;
 
 /**
  * Macro node for method CompilerDirectives#unsafeCast.
  */
 @NodeInfo
-public class UnsafeTypeCastMacroNode extends NeverPartOfCompilationNode implements Simplifiable {
+public final class UnsafeTypeCastMacroNode extends MacroStateSplitNode implements Simplifiable {
 
+    public static final NodeClass<UnsafeTypeCastMacroNode> TYPE = NodeClass.create(UnsafeTypeCastMacroNode.class);
     private static final int OBJECT_ARGUMENT_INDEX = 0;
     private static final int CLASS_ARGUMENT_INDEX = 1;
     private static final int CONDITION_ARGUMENT_INDEX = 2;
@@ -45,7 +47,7 @@
     private static final int ARGUMENT_COUNT = 4;
 
     public UnsafeTypeCastMacroNode(Invoke invoke) {
-        super(invoke, "The class of the unsafe cast could not be reduced to a compile time constant.");
+        super(TYPE, invoke);
         assert arguments.size() == ARGUMENT_COUNT;
     }
 
@@ -64,7 +66,7 @@
             } else {
                 Stamp piStamp = StampFactory.declaredTrusted(lookupJavaType, nonNullArgument.asJavaConstant().asInt() != 0);
                 ConditionAnchorNode valueAnchorNode = graph().add(
-                                new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()))));
+                                new ConditionAnchorNode(CompareNode.createCompareNode(graph(), Condition.EQ, conditionArgument, ConstantNode.forBoolean(true, graph()), tool.getConstantReflection())));
                 PiNode piCast = graph().unique(new PiNode(objectArgument, piStamp, valueAnchorNode));
                 replaceAtUsages(piCast);
                 graph().replaceFixedWithFixed(this, valueAnchorNode);
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -43,7 +43,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.class)) {
+        for (MethodCallTargetNode methodCallTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
             if (methodCallTarget.isAlive()) {
                 InvokeKind invokeKind = methodCallTarget.invokeKind();
                 if (invokeKind.isDirect()) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,7 +37,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        for (NewFrameNode virtualFrame : graph.getNodes(NewFrameNode.class)) {
+        for (NewFrameNode virtualFrame : graph.getNodes(NewFrameNode.TYPE)) {
             for (MethodCallTargetNode callTarget : virtualFrame.usages().filter(MethodCallTargetNode.class)) {
                 if (callTarget.invoke() != null) {
                     String properties = callTarget.getDebugProperties().toString();
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -23,43 +23,15 @@
 package com.oracle.graal.truffle.substitutions;
 
 import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.truffle.nodes.asserts.*;
 import com.oracle.truffle.api.*;
 
 @ClassSubstitution(CompilerAsserts.class)
 public class CompilerAssertsSubstitutions {
 
-    @MacroSubstitution(macro = NeverPartOfCompilationNode.class, isStatic = true)
-    public static native void neverPartOfCompilation();
-
-    @MacroSubstitution(macro = NeverPartOfCompilationNode.class, isStatic = true)
-    public static native void neverPartOfCompilation(String message);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native boolean compilationConstant(boolean value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native byte compilationConstant(byte value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native char compilationConstant(char value);
+    @MethodSubstitution
+    public static void neverPartOfCompilation(@SuppressWarnings("unused") String message) {
+        NeverPartOfCompilationNode.apply("Never part of compilation");
+    }
 
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native short compilationConstant(short value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native int compilationConstant(int value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native long compilationConstant(long value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native float compilationConstant(float value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native double compilationConstant(double value);
-
-    @MacroSubstitution(macro = CompilationConstantNode.class, isStatic = true)
-    public static native Object compilationConstant(Object value);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Sat Feb 21 19:55:33 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)
@@ -74,103 +73,13 @@
     @MacroSubstitution(macro = BailoutNode.class, isStatic = true)
     public static native void bailout(String reason);
 
-    @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);
+    public static boolean isCompilationConstant(Object value) {
+        return IsCompilationConstantNode.check(value);
     }
 
     @MethodSubstitution
     public static void materialize(Object obj) {
         ForceMaterializeNode.force(obj);
     }
-
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/FrameWithoutBoxingSubstitutions.java	Sat Feb 21 19:55:33 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/OptimizedCallTargetSubstitutions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,7 +33,7 @@
 public class OptimizedCallTargetSubstitutions {
 
     @MethodSubstitution
-    private static FrameWithoutBoxing createFrame(FrameDescriptor descriptor, Object[] args) {
+    private static VirtualFrame createFrame(FrameDescriptor descriptor, Object[] args) {
         return NewFrameNode.allocate(FrameWithoutBoxing.class, descriptor, args);
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,30 +26,105 @@
 
 import java.util.concurrent.*;
 
-import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.type.*;
 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.java.GraphBuilderPlugin.InvocationPlugin;
+import com.oracle.graal.java.InvocationPlugins.Registration;
+import com.oracle.graal.java.InvocationPlugins.Registration.Receiver;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.truffle.*;
 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.*;
 
 /**
- * Provider of {@link GraphBuilderPlugin}s for Truffle classes.
+ * Provides {@link InvocationPlugin}s for Truffle classes.
  */
 public class TruffleGraphBuilderPlugins {
-    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
+    public static void registerInvocationPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+
+        registerOptimizedAssumptionPlugins(metaAccess, plugins);
+        registerExactMathPlugins(metaAccess, plugins);
+        registerCompilerDirectivesPlugins(metaAccess, plugins);
+        registerOptimizedCallTargetPlugins(metaAccess, plugins);
+        registerUnsafeAccessImplPlugins(metaAccess, plugins);
+
+        if (TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue()) {
+            registerFrameWithoutBoxingPlugins(metaAccess, plugins);
+        } else {
+            registerFrameWithBoxingPlugins(metaAccess, plugins);
+        }
+
+    }
+
+    public static void registerOptimizedAssumptionPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, OptimizedAssumption.class);
+        r.register1("isValid", Receiver.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode arg) {
+                if (arg.isConstant()) {
+                    Constant constant = arg.asConstant();
+                    OptimizedAssumption assumption = builder.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant);
+                    builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(assumption.isValid())));
+                    if (assumption.isValid()) {
+                        builder.getAssumptions().record(new AssumptionValidAssumption(assumption));
+                    }
+                } else {
+                    throw builder.bailout("assumption could not be reduced to a constant");
+                }
+                return true;
+            }
+        });
+    }
 
-        // CompilerDirectives.class
+    public static void registerExactMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, ExactMath.class);
+        r.register2("addExact", Integer.TYPE, Integer.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                builder.push(Kind.Int.getStackKind(), builder.append(new IntegerAddExactNode(x, y)));
+                return true;
+            }
+        });
+        r.register2("addExact", Long.TYPE, Long.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                builder.push(Kind.Long, builder.append(new IntegerAddExactNode(x, y)));
+                return true;
+            }
+        });
+        r.register2("subtractExact", Integer.TYPE, Integer.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                builder.push(Kind.Int.getStackKind(), builder.append(new IntegerSubExactNode(x, y)));
+                return true;
+            }
+        });
+        r.register2("subtractExact", Long.TYPE, Long.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                builder.push(Kind.Long, builder.append(new IntegerSubExactNode(x, y)));
+                return true;
+            }
+        });
+        r.register2("multiplyExact", Integer.TYPE, Integer.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                builder.push(Kind.Int.getStackKind(), builder.append(new IntegerMulExactNode(x, y)));
+                return true;
+            }
+        });
+        r.register2("multiplyExact", Long.TYPE, Long.TYPE, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                builder.push(Kind.Long, builder.append(new IntegerMulExactNode(x, y)));
+                return true;
+            }
+        });
+    }
+
+    public static void registerCompilerDirectivesPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
         Registration r = new Registration(plugins, metaAccess, CompilerDirectives.class);
         r.register0("inInterpreter", new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder) {
@@ -87,25 +162,26 @@
         });
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode probability, ValueNode condition) {
-                builder.append(new BranchProbabilityNode(probability, condition));
+                builder.push(Kind.Boolean.getStackKind(), builder.append(new BranchProbabilityNode(probability, condition)));
                 return true;
             }
         });
         r.register1("bailout", String.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode message) {
                 if (message.isConstant()) {
-                    throw new BailoutException(message.asConstant().toValueString());
+                    throw builder.bailout(message.asConstant().toValueString());
                 }
-                throw new BailoutException("bailout (message is not compile-time constant, so no additional information is available)");
+                throw builder.bailout("bailout (message is not compile-time constant, so no additional information is available)");
             }
         });
         r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode value) {
                 if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
                     builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(true)));
-                    return true;
+                } else {
+                    builder.push(Kind.Boolean.getStackKind(), builder.append(new IsCompilationConstantNode(value)));
                 }
-                return false;
+                return true;
             }
         });
         r.register1("materialize", Object.class, new InvocationPlugin() {
@@ -114,24 +190,48 @@
                 return true;
             }
         });
+    }
 
-        // OptimizedCallTarget.class
-        r = new Registration(plugins, metaAccess, OptimizedCallTarget.class);
+    public static void registerOptimizedCallTargetPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, OptimizedCallTarget.class);
         r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode arg1, ValueNode arg2) {
-                builder.push(Kind.Object, builder.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(FrameWithoutBoxing.class)), arg1, arg2)));
+                Class<?> frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class;
+                builder.push(Kind.Object, builder.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), arg1, arg2)));
                 return true;
             }
         });
+    }
 
-        // FrameWithoutBoxing.class
-        r = new Registration(plugins, metaAccess, FrameWithoutBoxing.class);
+    public static void registerFrameWithoutBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, FrameWithoutBoxing.class);
+        registerMaterialize(r);
+        registerUnsafeCast(r);
+        registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+    }
+
+    public static void registerFrameWithBoxingPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, FrameWithBoxing.class);
+        registerMaterialize(r);
+        registerUnsafeCast(r);
+    }
+
+    public static void registerUnsafeAccessImplPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
+        registerUnsafeCast(r);
+        registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
+    }
+
+    private static void registerMaterialize(Registration r) {
         r.register1("materialize", Receiver.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode frame) {
-                builder.append(new MaterializeFrameNode(frame));
+                builder.push(Kind.Object, builder.append(new MaterializeFrameNode(frame)));
                 return true;
             }
         });
+    }
+
+    private static void registerUnsafeCast(Registration r) {
         r.register4("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext builder, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) {
                 if (clazz.isConstant() && nonNull.isConstant()) {
@@ -140,19 +240,40 @@
                     if (javaType == null) {
                         builder.push(Kind.Object, object);
                     } else {
-                        Stamp piStamp = StampFactory.declaredTrusted(javaType, nonNull.asJavaConstant().asInt() != 0);
-                        ConditionAnchorNode valueAnchorNode = builder.append(new ConditionAnchorNode(CompareNode.createCompareNode(object.graph(), Condition.EQ, condition,
-                                        ConstantNode.forBoolean(true, object.graph()))));
+                        Stamp piStamp = null;
+                        if (javaType.isArray()) {
+                            if (nonNull.asJavaConstant().asInt() != 0) {
+                                piStamp = StampFactory.exactNonNull(javaType);
+                            } else {
+                                piStamp = StampFactory.exact(javaType);
+                            }
+                        } else {
+                            piStamp = StampFactory.declaredTrusted(javaType, nonNull.asJavaConstant().asInt() != 0);
+                        }
+                        LogicNode compareNode = CompareNode.createCompareNode(object.graph(), Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), constantReflection);
+                        boolean skipAnchor = false;
+                        if (compareNode instanceof LogicConstantNode) {
+                            LogicConstantNode logicConstantNode = (LogicConstantNode) compareNode;
+                            if (logicConstantNode.getValue()) {
+                                skipAnchor = true;
+                            }
+                        }
+                        ConditionAnchorNode valueAnchorNode = null;
+                        if (!skipAnchor) {
+                            valueAnchorNode = builder.append(new ConditionAnchorNode(compareNode));
+                        }
                         PiNode piCast = builder.append(new PiNode(object, piStamp, valueAnchorNode));
                         builder.push(Kind.Object, piCast);
                     }
                     return true;
                 }
-                // TODO: should we throw GraalInternalError.shouldNotReachHere() here?
-                return false;
+                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}) {
+    }
+
+    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;
@@ -178,7 +299,7 @@
                 } else {
                     locationIdentity = ObjectLocationIdentity.create(location.asJavaConstant());
                 }
-                CompareNode compare = builder.append(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph())));
+                LogicNode compare = builder.append(CompareNode.createCompareNode(Condition.EQ, condition, ConstantNode.forBoolean(true, object.graph()), builder.getConstantReflection()));
                 builder.push(returnKind.getStackKind(), builder.append(new UnsafeLoadNode(object, offset, returnKind, locationIdentity, compare)));
                 return true;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/UnsafeAccessSubstitutions.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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/nodes/MaterializedObjectState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializedObjectState.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -31,8 +31,9 @@
  * This class encapsulated the materialized state of an escape analyzed object.
  */
 @NodeInfo
-public class MaterializedObjectState extends EscapeObjectState implements Node.ValueNumberable {
+public final class MaterializedObjectState extends EscapeObjectState implements Node.ValueNumberable {
 
+    public static final NodeClass<MaterializedObjectState> TYPE = NodeClass.create(MaterializedObjectState.class);
     @Input ValueNode materializedValue;
 
     public ValueNode materializedValue() {
@@ -40,7 +41,7 @@
     }
 
     public MaterializedObjectState(VirtualObjectNode object, ValueNode materializedValue) {
-        super(object);
+        super(TYPE, object);
         this.materializedValue = materializedValue;
     }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -33,8 +33,9 @@
  * This class encapsulated the virtual state of an escape analyzed object.
  */
 @NodeInfo
-public class VirtualObjectState extends EscapeObjectState implements Node.ValueNumberable {
+public final class VirtualObjectState extends EscapeObjectState implements Node.ValueNumberable {
 
+    public static final NodeClass<VirtualObjectState> TYPE = NodeClass.create(VirtualObjectState.class);
     @Input NodeInputList<ValueNode> values;
 
     public NodeInputList<ValueNode> values() {
@@ -42,13 +43,13 @@
     }
 
     public VirtualObjectState(VirtualObjectNode object, ValueNode[] values) {
-        super(object);
+        super(TYPE, object);
         assert object.entryCount() == values.length;
         this.values = new NodeInputList<>(this, values);
     }
 
     public VirtualObjectState(VirtualObjectNode object, List<ValueNode> values) {
-        super(object);
+        super(TYPE, object);
         assert object.entryCount() == values.size();
         this.values = new NodeInputList<>(this, values);
     }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Sat Feb 21 19:55:33 2015 +0100
@@ -108,14 +108,14 @@
         add("add virtual mapping", new Effect() {
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
-                assert node.isAlive() && !state.isAlive() && !state.isDeleted();
+                assert node.isAlive() && !state.isDeleted();
                 FrameState stateAfter = node;
                 for (int i = 0; i < stateAfter.virtualObjectMappingCount(); i++) {
                     if (stateAfter.virtualObjectMappingAt(i).object() == state.object()) {
                         stateAfter.virtualObjectMappings().remove(i);
                     }
                 }
-                stateAfter.addVirtualObjectMapping(graph.unique(state));
+                stateAfter.addVirtualObjectMapping(state.isAlive() ? state : graph.unique(state));
             }
 
             @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ObjectState.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,11 +24,13 @@
 
 import java.util.*;
 
+import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.virtual.nodes.*;
 
 /**
  * This class describes the state of a virtual object while iterating over the graph. It describes
@@ -37,6 +39,9 @@
  */
 public class ObjectState extends Virtualizable.State {
 
+    public static final DebugMetric CREATE_ESCAPED_OBJECT_STATE = Debug.metric("CreateEscapeObjectState");
+    public static final DebugMetric GET_ESCAPED_OBJECT_STATE = Debug.metric("GetEscapeObjectState");
+
     final VirtualObjectNode virtual;
 
     private EscapeState state;
@@ -44,6 +49,8 @@
     private ValueNode materializedValue;
     private LockState locks;
 
+    private EscapeObjectState cachedState;
+
     public ObjectState(VirtualObjectNode virtual, ValueNode[] entries, EscapeState state, List<MonitorIdNode> locks) {
         this(virtual, entries, state, (LockState) null);
         for (int i = locks.size() - 1; i >= 0; i--) {
@@ -71,12 +78,23 @@
         materializedValue = other.materializedValue;
         locks = other.locks;
         state = other.state;
+        cachedState = other.cachedState;
     }
 
     public ObjectState cloneState() {
         return new ObjectState(this);
     }
 
+    public EscapeObjectState createEscapeObjectState() {
+        GET_ESCAPED_OBJECT_STATE.increment();
+        if (cachedState == null) {
+            CREATE_ESCAPED_OBJECT_STATE.increment();
+            cachedState = isVirtual() ? new VirtualObjectState(virtual, entries) : new MaterializedObjectState(virtual, materializedValue);
+        }
+        return cachedState;
+
+    }
+
     @Override
     public EscapeState getState() {
         return state;
@@ -104,7 +122,10 @@
 
     public void setEntry(int index, ValueNode value) {
         assert isVirtual();
-        entries[index] = value;
+        if (entries[index] != value) {
+            cachedState = null;
+            entries[index] = value;
+        }
     }
 
     public void escape(ValueNode materialized, EscapeState newState) {
@@ -112,6 +133,7 @@
         state = newState;
         materializedValue = materialized;
         entries = null;
+        cachedState = null;
         assert !isVirtual();
     }
 
@@ -123,7 +145,10 @@
 
     public void updateMaterializedValue(ValueNode value) {
         assert !isVirtual();
-        materializedValue = value;
+        if (value != materializedValue) {
+            cachedState = null;
+            materializedValue = value;
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Sat Feb 21 19:55:33 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/PartialEscapeBlockState.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Sat Feb 21 19:55:33 2015 +0100
@@ -120,6 +120,7 @@
         ValueNode[] entries = obj.getEntries();
         ValueNode representation = virtual.getMaterializedRepresentation(fixed, entries, obj.getLocks());
         obj.escape(representation, state);
+        PartialEscapeClosure.updateStatesForMaterialized(this, obj);
         if (representation instanceof AllocatedObjectNode) {
             objects.add((AllocatedObjectNode) representation);
             locks.add(LockState.asList(obj.getLocks()));
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Sat Feb 21 19:55:33 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.*;
@@ -39,7 +38,6 @@
 import com.oracle.graal.nodes.spi.Virtualizable.EscapeState;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.schedule.*;
-import com.oracle.graal.virtual.nodes.*;
 
 public abstract class PartialEscapeClosure<BlockT extends PartialEscapeBlockState<BlockT>> extends EffectsClosure<BlockT> {
 
@@ -94,8 +92,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 +107,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);
     }
 
     /**
@@ -163,7 +161,7 @@
             frameState.applyToNonVirtual(new CollectVirtualObjectsClosure(virtual, effects, state));
             collectLockedVirtualObjects(state, virtual);
             collectReferencedVirtualObjects(state, virtual);
-            addVirtualMappings(state, effects, frameState, virtual);
+            addVirtualMappings(effects, frameState, virtual);
         }
     }
 
@@ -177,15 +175,9 @@
         return frameState;
     }
 
-    private void addVirtualMappings(final BlockT state, final GraphEffectList effects, FrameState frameState, Set<ObjectState> virtual) {
+    private static void addVirtualMappings(GraphEffectList effects, FrameState frameState, Set<ObjectState> virtual) {
         for (ObjectState obj : virtual) {
-            EscapeObjectState v;
-            if (obj.isVirtual()) {
-                v = createVirtualObjectState(state, obj);
-            } else {
-                v = new MaterializedObjectState(obj.virtual, obj.getMaterializedValue());
-            }
-            effects.addVirtualMapping(frameState, v);
+            effects.addVirtualMapping(frameState, obj.createEscapeObjectState());
         }
     }
 
@@ -207,24 +199,7 @@
         }
     }
 
-    private EscapeObjectState createVirtualObjectState(final BlockT state, ObjectState obj) {
-        EscapeObjectState v;
-        ValueNode[] fieldState = obj.getEntries().clone();
-        for (int i = 0; i < fieldState.length; i++) {
-            ObjectState valueObj = getObjectState(state, fieldState[i]);
-            if (valueObj != null) {
-                if (valueObj.isVirtual()) {
-                    fieldState[i] = valueObj.virtual;
-                } else {
-                    fieldState[i] = valueObj.getMaterializedValue();
-                }
-            }
-        }
-        v = new VirtualObjectState(obj.virtual, fieldState);
-        return v;
-    }
-
-    private void collectLockedVirtualObjects(final BlockT state, final Set<ObjectState> virtual) {
+    private void collectLockedVirtualObjects(final BlockT state, Set<ObjectState> virtual) {
         for (ObjectState obj : state.getStates()) {
             if (obj.isVirtual() && obj.hasLocks()) {
                 virtual.add(obj);
@@ -240,6 +215,7 @@
         if (obj.getState() == EscapeState.Virtual) {
             metric.increment();
             state.materializeBefore(materializeBefore, obj.virtual, EscapeState.Materialized, effects);
+            updateStatesForMaterialized(state, obj);
             assert !obj.isVirtual();
             return true;
         } else {
@@ -248,6 +224,20 @@
         }
     }
 
+    public static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, ObjectState obj) {
+        // update all existing states with the newly materialized object
+        for (ObjectState objState : state.objectStates.values()) {
+            if (objState.isVirtual()) {
+                ValueNode[] entries = objState.getEntries();
+                for (int i = 0; i < entries.length; i++) {
+                    if (entries[i] == obj.virtual) {
+                        objState.setEntry(i, obj.getMaterializedValue());
+                    }
+                }
+            }
+        }
+    }
+
     private boolean replaceWithMaterialized(Node value, Node usage, FixedNode materializeBefore, BlockT state, ObjectState obj, GraphEffectList effects, DebugMetric metric) {
         boolean materialized = ensureMaterialized(state, obj, materializeBefore, effects, metric);
         effects.replaceFirstInput(usage, value, obj.getMaterializedValue());
@@ -539,8 +529,8 @@
                 int valueIndex = 0;
                 while (valueIndex < values.length) {
                     for (int i = 1; i < objStates.length; i++) {
-                        ValueNode[] fields = objStates[i].getEntries();
-                        if (phis[valueIndex] == null && values[valueIndex] != fields[valueIndex]) {
+                        ValueNode field = objStates[i].getEntry(valueIndex);
+                        if (phis[valueIndex] == null && values[valueIndex] != field) {
                             phis[valueIndex] = new ValuePhiNode(values[valueIndex].stamp().unrestricted(), merge);
                         }
                     }
@@ -597,14 +587,16 @@
                 if (!objStates[i].isVirtual()) {
                     break;
                 }
-                ValueNode[] entries = objStates[i].getEntries();
-                if (entries[entryIndex] instanceof VirtualObjectNode) {
-                    ObjectState obj = blockStates.get(i).getObjectState((VirtualObjectNode) entries[entryIndex]);
+                ValueNode entry = objStates[i].getEntry(entryIndex);
+                if (entry instanceof VirtualObjectNode) {
+                    ObjectState obj = blockStates.get(i).getObjectState((VirtualObjectNode) entry);
                     Block predecessor = mergeBlock.getPredecessors().get(i);
                     materialized |= ensureMaterialized(blockStates.get(i), obj, predecessor.getEndNode(), blockEffects.get(predecessor), METRIC_MATERIALIZATIONS_MERGE);
-                    entries[entryIndex] = obj.getMaterializedValue();
+                    if (objStates[i].isVirtual()) {
+                        objStates[i].setEntry(entryIndex, entry = obj.getMaterializedValue());
+                    }
                 }
-                afterMergeEffects.addPhiInput(phi, entries[entryIndex]);
+                afterMergeEffects.addPhiInput(phi, entry);
             }
             return materialized;
         }
@@ -618,7 +610,7 @@
                 if (!state.isVirtual()) {
                     break;
                 }
-                afterMergeEffects.addPhiInput(phi, state.getEntries()[entryIndex]);
+                afterMergeEffects.addPhiInput(phi, state.getEntry(entryIndex));
             }
         }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Sat Feb 21 19:55:33 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.graal.word/src/com/oracle/graal/word/Signed.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,7 +26,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this + val)}.
-     * 
+     *
      * @param val value to be added to this Signed.
      * @return {@code this + val}
      */
@@ -34,7 +34,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this - val)}.
-     * 
+     *
      * @param val value to be subtracted from this Signed.
      * @return {@code this - val}
      */
@@ -42,7 +42,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this * val)}.
-     * 
+     *
      * @param val value to be multiplied by this Signed.
      * @return {@code this * val}
      */
@@ -50,7 +50,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this / val)}.
-     * 
+     *
      * @param val value by which this Signed is to be divided.
      * @return {@code this / val}
      */
@@ -58,7 +58,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this % val)}.
-     * 
+     *
      * @param val value by which this Signed is to be divided, and the remainder computed.
      * @return {@code this % val}
      */
@@ -66,7 +66,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this << n)}.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this << n}
      */
@@ -74,7 +74,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      */
@@ -83,7 +83,7 @@
     /**
      * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
      * if and only if this and val are both negative.)
-     * 
+     *
      * @param val value to be AND'ed with this Signed.
      * @return {@code this & val}
      */
@@ -92,7 +92,7 @@
     /**
      * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
      * if and only if either this or val is negative.)
-     * 
+     *
      * @param val value to be OR'ed with this Signed.
      * @return {@code this | val}
      */
@@ -101,7 +101,7 @@
     /**
      * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
      * if and only if exactly one of this and val are negative.)
-     * 
+     *
      * @param val value to be XOR'ed with this Signed.
      * @return {@code this ^ val}
      */
@@ -110,14 +110,14 @@
     /**
      * Returns a Signed whose value is {@code (~this)}. (This method returns a negative value if and
      * only if this Signed is non-negative.)
-     * 
+     *
      * @return {@code ~this}
      */
     Signed not();
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this == val}
      */
@@ -125,7 +125,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this != val}
      */
@@ -133,7 +133,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this < val}
      */
@@ -141,7 +141,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this <= val}
      */
@@ -149,7 +149,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this > val}
      */
@@ -157,7 +157,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this >= val}
      */
@@ -165,7 +165,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this + val)}.
-     * 
+     *
      * @param val value to be added to this Signed.
      * @return {@code this + val}
      */
@@ -173,7 +173,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this - val)}.
-     * 
+     *
      * @param val value to be subtracted from this Signed.
      * @return {@code this - val}
      */
@@ -181,7 +181,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this * val)}.
-     * 
+     *
      * @param val value to be multiplied by this Signed.
      * @return {@code this * val}
      */
@@ -189,7 +189,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this / val)}.
-     * 
+     *
      * @param val value by which this Signed is to be divided.
      * @return {@code this / val}
      */
@@ -197,7 +197,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this % val)}.
-     * 
+     *
      * @param val value by which this Signed is to be divided, and the remainder computed.
      * @return {@code this % val}
      */
@@ -205,7 +205,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this << n)}.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this << n}
      */
@@ -213,7 +213,7 @@
 
     /**
      * Returns a Signed whose value is {@code (this >> n)}. Sign extension is performed.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      */
@@ -222,7 +222,7 @@
     /**
      * Returns a Signed whose value is {@code (this & val)}. (This method returns a negative Signed
      * if and only if this and val are both negative.)
-     * 
+     *
      * @param val value to be AND'ed with this Signed.
      * @return {@code this & val}
      */
@@ -231,7 +231,7 @@
     /**
      * Returns a Signed whose value is {@code (this | val)}. (This method returns a negative Signed
      * if and only if either this or val is negative.)
-     * 
+     *
      * @param val value to be OR'ed with this Signed.
      * @return {@code this | val}
      */
@@ -240,7 +240,7 @@
     /**
      * Returns a Signed whose value is {@code (this ^ val)}. (This method returns a negative Signed
      * if and only if exactly one of this and val are negative.)
-     * 
+     *
      * @param val value to be XOR'ed with this Signed.
      * @return {@code this ^ val}
      */
@@ -248,7 +248,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this == val}
      */
@@ -256,7 +256,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this != val}
      */
@@ -264,7 +264,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this < val}
      */
@@ -272,7 +272,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this <= val}
      */
@@ -280,7 +280,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this > val}
      */
@@ -288,7 +288,7 @@
 
     /**
      * Compares this Signed with the specified value.
-     * 
+     *
      * @param val value to which this Signed is to be compared.
      * @return {@code this >= val}
      */
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,7 +26,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this + val)}.
-     * 
+     *
      * @param val value to be added to this Unsigned.
      * @return {@code this + val}
      */
@@ -34,7 +34,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this - val)}.
-     * 
+     *
      * @param val value to be subtracted from this Unsigned.
      * @return {@code this - val}
      */
@@ -42,7 +42,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this * val)}.
-     * 
+     *
      * @param val value to be multiplied by this Unsigned.
      * @return {@code this * val}
      */
@@ -50,7 +50,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this / val)}.
-     * 
+     *
      * @param val value by which this Unsigned is to be divided.
      * @return {@code this / val}
      */
@@ -58,7 +58,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this % val)}.
-     * 
+     *
      * @param val value by which this Unsigned is to be divided, and the remainder computed.
      * @return {@code this % val}
      */
@@ -66,7 +66,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this << n)}.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this << n}
      */
@@ -74,7 +74,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this >>> n)}. No sign extension is performed.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      */
@@ -82,7 +82,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this & val)}.
-     * 
+     *
      * @param val value to be AND'ed with this Unsigned.
      * @return {@code this & val}
      */
@@ -90,7 +90,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this | val)}.
-     * 
+     *
      * @param val value to be OR'ed with this Unsigned.
      * @return {@code this | val}
      */
@@ -98,7 +98,7 @@
 
     /**
      * Returns a Unsigned whose value is {@code (this ^ val)}.
-     * 
+     *
      * @param val value to be XOR'ed with this Unsigned.
      * @return {@code this ^ val}
      */
@@ -106,14 +106,14 @@
 
     /**
      * Returns a Unsigned whose value is {@code (~this)}.
-     * 
+     *
      * @return {@code ~this}
      */
     Unsigned not();
 
     /**
      * Compares this Unsigned with the specified value.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this == val}
      */
@@ -121,7 +121,7 @@
 
     /**
      * Compares this Unsigned with the specified value.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this != val}
      */
@@ -129,7 +129,7 @@
 
     /**
      * Compares this Unsigned with the specified value.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this < val}
      */
@@ -137,7 +137,7 @@
 
     /**
      * Compares this Unsigned with the specified value.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this <= val}
      */
@@ -145,7 +145,7 @@
 
     /**
      * Compares this Unsigned with the specified value.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this > val}
      */
@@ -153,7 +153,7 @@
 
     /**
      * Compares this Unsigned with the specified value.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this >= val}
      */
@@ -164,7 +164,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to be added to this Unsigned.
      * @return {@code this + val}
      */
@@ -175,7 +175,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to be subtracted from this Unsigned.
      * @return {@code this - val}
      */
@@ -186,7 +186,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to be multiplied by this Unsigned.
      * @return {@code this * val}
      */
@@ -197,7 +197,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value by which this Unsigned is to be divided.
      * @return {@code this / val}
      */
@@ -208,7 +208,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value by which this Unsigned is to be divided, and the remainder computed.
      * @return {@code this % val}
      */
@@ -219,7 +219,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this << n}
      */
@@ -230,7 +230,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param n shift distance, in bits.
      * @return {@code this >> n}
      */
@@ -241,7 +241,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to be AND'ed with this Unsigned.
      * @return {@code this & val}
      */
@@ -252,7 +252,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to be OR'ed with this Unsigned.
      * @return {@code this | val}
      */
@@ -263,7 +263,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to be XOR'ed with this Unsigned.
      * @return {@code this ^ val}
      */
@@ -274,7 +274,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this == val}
      */
@@ -285,7 +285,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this != val}
      */
@@ -296,7 +296,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this < val}
      */
@@ -307,7 +307,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this <= val}
      */
@@ -318,7 +318,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this > val}
      */
@@ -329,7 +329,7 @@
      * <p>
      * Note that the right operand is a signed value, while the operation is performed unsigned.
      * Therefore, the result is only well-defined for positive right operands.
-     * 
+     *
      * @param val value to which this Unsigned is to be compared.
      * @return {@code this >= val}
      */
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,7 +44,8 @@
  * this node can be canonicalized to a {@link IndexedLocationNode} or {@link ConstantLocationNode}.
  */
 @NodeInfo
-public class SnippetLocationNode extends LocationNode implements Canonicalizable {
+public final class SnippetLocationNode extends LocationNode implements Canonicalizable {
+    public static final NodeClass<SnippetLocationNode> TYPE = NodeClass.create(SnippetLocationNode.class);
 
     protected final SnippetReflectionProvider snippetReflection;
 
@@ -58,7 +59,7 @@
     }
 
     public SnippetLocationNode(@InjectedNodeParameter SnippetReflectionProvider snippetReflection, ValueNode locationIdentity, ValueNode displacement, ValueNode index, ValueNode indexScaling) {
-        super(StampFactory.object());
+        super(TYPE, StampFactory.object());
         this.snippetReflection = snippetReflection;
         this.locationIdentity = locationIdentity;
         this.displacement = displacement;
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,8 +36,9 @@
  * impact on the pointer maps for the GC, so it must not be scheduled or optimized away.
  */
 @NodeInfo
-public class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
+public final class WordCastNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
 
+    public static final NodeClass<WordCastNode> TYPE = NodeClass.create(WordCastNode.class);
     @Input ValueNode input;
 
     public static WordCastNode wordToObject(ValueNode input, Kind wordKind) {
@@ -51,7 +52,7 @@
     }
 
     public WordCastNode(Stamp stamp, ValueNode input) {
-        super(stamp);
+        super(TYPE, stamp);
         this.input = input;
     }
 
@@ -65,6 +66,17 @@
             /* If the cast is unused, it can be eliminated. */
             return input;
         }
+
+        assert !stamp().isCompatible(input.stamp());
+        if (input.isConstant()) {
+            /* Null pointers are uncritical for GC, so they can be constant folded. */
+            if (input.asJavaConstant().isNull()) {
+                return ConstantNode.forIntegerStamp(stamp(), 0);
+            } else if (input.asJavaConstant().getKind().isNumericInteger() && input.asJavaConstant().asLong() == 0) {
+                return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, tool.getMetaAccess());
+            }
+        }
+
         return this;
     }
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Sat Feb 21 19:55:33 2015 +0100
@@ -113,6 +113,8 @@
     protected void rewriteNode(StructuredGraph graph, Node node) {
         if (node instanceof CheckCastNode) {
             rewriteCheckCast(graph, (CheckCastNode) node);
+        } else if (node instanceof PiNode) {
+            rewritePi(graph, (PiNode) node);
         } else if (node instanceof LoadFieldNode) {
             rewriteLoadField(graph, (LoadFieldNode) node);
         } else if (node instanceof AccessIndexedNode) {
@@ -133,6 +135,16 @@
     }
 
     /**
+     * Remove casts between word types (which by now no longer have kind Object).
+     */
+    protected void rewritePi(StructuredGraph graph, PiNode node) {
+        if (node.getKind() == wordKind) {
+            node.replaceAtUsages(node.object());
+            graph.removeFloating(node);
+        }
+    }
+
+    /**
      * Fold constant field reads, e.g. enum constants.
      */
     protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) {
--- a/graal/com.oracle.nfi/src/com/oracle/nfi/api/NativeFunctionPointer.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.nfi/src/com/oracle/nfi/api/NativeFunctionPointer.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,14 +33,14 @@
 
     /**
      * Returns the name of the function.
-     * 
+     *
      * @return name of the function
      */
     String getName();
 
     /**
      * Returns the raw function pointer value.
-     * 
+     *
      * @return raw function pointer value
      */
     long getRawValue();
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/AssumptionsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/CodeFormatTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ContainsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteMethodTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/FallbackTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImportGuardsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/InsertBeforeTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/MethodGuardsWithArgumentsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/NegatedGuardsTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ReachabilityTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ShortCircuitTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SourceSectionTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationFallthroughTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/SpecializationGroupingTest.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TestHelper.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Implies.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/NodeAssumptions.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Specialization.java	Sat Feb 21 19:55:33 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/TypeSystem.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java	Sat Feb 21 19:55:33 2015 +0100
@@ -37,7 +37,7 @@
  * concrete type is found first when searching the list sequentially for the type of a given generic
  * value.
  * </p>
- * 
+ *
  * <p>
  * Each {@link #value()} is represented as a java type. A type can specify two annotations:
  * {@link TypeCheck} and {@link TypeCast}. The {@link TypeCheck} checks whether a given generic
@@ -51,30 +51,30 @@
  * accept also {@link Integer} values, implicitly converting them to {@link Double} . This example
  * points out how we express implicit type conversions.
  * </p>
- * 
+ *
  * <p>
  * <b>Example:</b> The {@link TypeSystem} contains the types {@link Boolean}, {@link Integer}, and
  * {@link Double}. The type {@link Object} is always used implicitly as the generic type represent
  * all values.
- * 
+ *
  * <pre>
- * 
+ *
  * {@literal @}TypeSystem(types = {boolean.class, int.class, double.class})
  * public abstract class ExampleTypeSystem {
- * 
+ *
  *     {@literal @}TypeCheck
  *     public boolean isInteger(Object value) {
  *         return value instanceof Integer || value instanceof Double;
  *     }
- * 
+ *
  *     {@literal @}TypeCast
  *     public double asInteger(Object value) {
  *         return ((Number)value).doubleValue();
  *     }
  * }
  * </pre>
- * 
- * 
+ *
+ *
  * @see TypeCast
  * @see TypeCheck
  */
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystemReference.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystemReference.java	Sat Feb 21 19:55:33 2015 +0100
@@ -31,7 +31,7 @@
 /**
  * References a {@link TypeSystem} on a node. Must be applied on a {@link Node} class. At least one
  * {@link TypeSystem} must be referenced in a {@link Node}'s type hierarchy.
- * 
+ *
  * @see TypeSystem
  * @see Node
  */
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLOptions.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/SpecializationNode.java	Sat Feb 21 19:55:33 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.object/src/com/oracle/truffle/api/object/DynamicObject.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.object/src/com/oracle/truffle/api/object/DynamicObject.java	Sat Feb 21 19:55:33 2015 +0100
@@ -27,11 +27,11 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.interop.*;
 
-public interface DynamicObject extends TypedObject, TruffleObject {
+public abstract class DynamicObject implements TypedObject, TruffleObject {
     /**
      * Get the object's current shape.
      */
-    Shape getShape();
+    public abstract Shape getShape();
 
     /**
      * Get property value.
@@ -40,7 +40,7 @@
      * @param defaultValue return value if property is not found
      * @return property value or defaultValue if object has no such property
      */
-    Object get(Object key, Object defaultValue);
+    public abstract Object get(Object key, Object defaultValue);
 
     /**
      * Set value of existing property.
@@ -49,7 +49,7 @@
      * @param value value to be set
      * @return {@code true} if successful or {@code false} if property not found
      */
-    boolean set(Object key, Object value);
+    public abstract boolean set(Object key, Object value);
 
     /**
      * Define new property or redefine existing property.
@@ -58,7 +58,7 @@
      * @param value value to be set
      * @param flags flags to be set
      */
-    void define(Object key, Object value, int flags);
+    public abstract void define(Object key, Object value, int flags);
 
     /**
      * Define new property with a static location or change existing property.
@@ -68,7 +68,7 @@
      * @param flags flags to be set
      * @param locationFactory factory function that creates a location for a given shape and value
      */
-    void define(Object key, Object value, int flags, LocationFactory locationFactory);
+    public abstract void define(Object key, Object value, int flags, LocationFactory locationFactory);
 
     /**
      * Change property flags.
@@ -77,7 +77,7 @@
      * @param newFlags flags to be set
      * @return {@code true} if successful or {@code false} if property not found
      */
-    boolean changeFlags(Object key, int newFlags);
+    public abstract boolean changeFlags(Object key, int newFlags);
 
     /**
      * Change property flags.
@@ -86,7 +86,7 @@
      * @param flagsUpdateFunction function updating old flags to new flags
      * @return {@code true} if successful or {@code false} if property not found
      */
-    boolean changeFlags(Object key, FlagsFunction flagsUpdateFunction);
+    public abstract boolean changeFlags(Object key, FlagsFunction flagsUpdateFunction);
 
     /**
      * Delete property.
@@ -94,17 +94,17 @@
      * @param key property identifier
      * @return {@code true} if successful or {@code false} if property not found
      */
-    boolean delete(Object key);
+    public abstract boolean delete(Object key);
 
     /**
      * Returns the number of properties in this object.
      */
-    int size();
+    public abstract int size();
 
     /**
      * Returns {@code true} if this object contains no properties.
      */
-    boolean isEmpty();
+    public abstract boolean isEmpty();
 
     /**
      * Set object shape and grow storage if necessary.
@@ -112,7 +112,7 @@
      * @param oldShape the object's current shape (must equal {@link #getShape()})
      * @param newShape the new shape to be set
      */
-    void setShapeAndGrow(Shape oldShape, Shape newShape);
+    public abstract void setShapeAndGrow(Shape oldShape, Shape newShape);
 
     /**
      * Set object shape and resize storage if necessary.
@@ -120,14 +120,14 @@
      * @param oldShape the object's current shape (must equal {@link #getShape()})
      * @param newShape the new shape to be set
      */
-    void setShapeAndResize(Shape oldShape, Shape newShape);
+    public abstract void setShapeAndResize(Shape oldShape, Shape newShape);
 
     /**
      * Ensure object shape is up-to-date.
      *
      * @return {@code true} if shape has changed
      */
-    boolean updateShape();
+    public abstract boolean updateShape();
 
     public interface FlagsFunction {
         int apply(int t);
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,13 +30,13 @@
 
 /**
  * <h3>Inserting Extra Nodes into the AST Transparently</h3>
- * 
+ *
  * <p>
  * The {@link Node} class provides a callback that is invoked whenever a node is adopted in an AST
  * by insertion or replacement. Node classes can override the {@code onAdopt()} method to run extra
  * functionality upon adoption.
  * </p>
- * 
+ *
  * <p>
  * This test demonstrates how node instances of a specific class can be automatically wrapped in
  * extra nodes when they are inserted into the AST.
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Sat Feb 21 19:55:33 2015 +0100
@@ -34,19 +34,19 @@
 
 /**
  * <h3>Replacing Nodes at Run Time</h3>
- * 
+ *
  * <p>
  * The structure of the Truffle tree can be changed at run time by replacing nodes using the
  * {@link Node#replace(Node)} method. This method will automatically change the child pointer in the
  * parent of the node and replace it with a pointer to the new node.
  * </p>
- * 
+ *
  * <p>
  * Replacing nodes is a costly operation, so it should not happen too often. The convention is that
  * the implementation of the Truffle nodes should ensure that there are maximal a small (and
  * constant) number of node replacements per Truffle node.
  * </p>
- * 
+ *
  * <p>
  * The next part of the Truffle API introduction is at {@link com.oracle.truffle.api.test.CallTest}.
  * </p>
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Sat Feb 21 19:55:33 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();
@@ -439,7 +439,7 @@
     }
 
     private abstract class TestLanguageNode extends Node {
-        public abstract Object execute(VirtualFrame frame);
+        public abstract Object execute(VirtualFrame vFrame);
 
         @Override
         public boolean isInstrumentable() {
@@ -492,17 +492,17 @@
         }
 
         @Override
-        public Object execute(VirtualFrame frame) {
-            probeNode.enter(child, frame);
+        public Object execute(VirtualFrame vFrame) {
+            probeNode.enter(child, vFrame);
             Object result;
 
             try {
-                result = child.execute(frame);
-                probeNode.returnValue(child, frame, result);
+                result = child.execute(vFrame);
+                probeNode.returnValue(child, vFrame, result);
             } catch (KillException e) {
                 throw (e);
             } catch (Exception e) {
-                probeNode.returnExceptional(child, frame, e);
+                probeNode.returnExceptional(child, vFrame, e);
                 throw (e);
             }
 
@@ -521,7 +521,7 @@
         }
 
         @Override
-        public Object execute(VirtualFrame frame) {
+        public Object execute(VirtualFrame vFrame) {
             return new Integer(this.value);
         }
     }
@@ -539,8 +539,8 @@
         }
 
         @Override
-        public Object execute(VirtualFrame frame) {
-            return new Integer(((Integer) leftChild.execute(frame)).intValue() + ((Integer) rightChild.execute(frame)).intValue());
+        public Object execute(VirtualFrame vFrame) {
+            return new Integer(((Integer) leftChild.execute(vFrame)).intValue() + ((Integer) rightChild.execute(vFrame)).intValue());
         }
     }
 
@@ -563,8 +563,8 @@
         }
 
         @Override
-        public Object execute(VirtualFrame frame) {
-            return body.execute(frame);
+        public Object execute(VirtualFrame vFrame) {
+            return body.execute(vFrame);
         }
 
         @Override
@@ -588,15 +588,15 @@
         public final Instrument instrument;
 
         public TestCounter() {
-            instrument = Instrument.create(new SimpleEventReceiver() {
+            instrument = Instrument.create(new SimpleEventListener() {
 
                 @Override
-                public void enter(Node node, VirtualFrame frame) {
+                public void enter(Node node, VirtualFrame vFrame) {
                     enterCount++;
                 }
 
                 @Override
-                public void returnAny(Node node, VirtualFrame frame) {
+                public void returnAny(Node node, VirtualFrame vFrame) {
                     leaveCount++;
                 }
             }, "Instrumentation Test Counter");
@@ -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,10 +692,10 @@
             // 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) {
+                public void enter(Node node, VirtualFrame vFrame) {
                     count++;
                 }
             }, "Instrumentation Test MultiCounter"));
--- a/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/.checkstyle_checks.xml	Sat Feb 21 19:55:33 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/CompilerAsserts.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerAsserts.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,7 +32,6 @@
  *
  */
 public class CompilerAsserts {
-
     /**
      * Assertion that this code position should never be reached during compilation. It can be used
      * for exceptional code paths or rare code paths that should never be included in a compilation
@@ -40,98 +39,29 @@
      * directive.
      */
     public static void neverPartOfCompilation() {
-    }
-
-    public static void neverPartOfCompilation(@SuppressWarnings("unused") String message) {
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static boolean compilationConstant(boolean value) {
-        return value;
+        neverPartOfCompilation("");
     }
 
     /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
+     * Assertion that this code position should never be reached during compilation. It can be used
+     * for exceptional code paths or rare code paths that should never be included in a compilation
+     * unit. See {@link CompilerDirectives#transferToInterpreter()} for the corresponding compiler
+     * directive.
      *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
+     * @param message text associated with the bailout exception
      */
-    public static byte compilationConstant(byte value) {
-        return value;
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static char compilationConstant(char value) {
-        return value;
+    public static void neverPartOfCompilation(String message) {
+        CompilerDirectives.bailout(message);
     }
 
     /**
      * Assertion that the corresponding value is reduced to a constant during compilation.
      *
      * @param value the value that must be constant during compilation
-     * @return the value given as parameter
      */
-    public static short compilationConstant(short value) {
-        return value;
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static int compilationConstant(int value) {
-        return value;
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static long compilationConstant(long value) {
-        return value;
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static float compilationConstant(float value) {
-        return value;
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static double compilationConstant(double value) {
-        return value;
-    }
-
-    /**
-     * Assertion that the corresponding value is reduced to a constant during compilation.
-     *
-     * @param value the value that must be constant during compilation
-     * @return the value given as parameter
-     */
-    public static Object compilationConstant(Object value) {
-        return value;
+    public static <T> void compilationConstant(Object value) {
+        if (!CompilerDirectives.isCompilationConstant(value)) {
+            neverPartOfCompilation("Value is not compilation constant");
+        }
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Sat Feb 21 19:55:33 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.
@@ -99,33 +80,20 @@
     /**
      * Returns a boolean indicating whether or not a given value is seen as constant in optimized
      * code. If this method is called in the interpreter this method will always return
-     * <code>false</code>. This API may be used in combination with {@link #inCompiledCode()} to
-     * implement compilation constant assertions in the following way:
-     *
-     * <pre>
-     * <code>
-     * void assertCompilationConstant(Object value) {
-     *   if (inCompiledCode()) {
-     *     if (!isCompilationConstant(value)) {
-     *       throw new AssertionError("Given value is not constant");
-     *     }
-     *   }
-     * }
-     * </code>
-     * </pre>
+     * <code>true</code>.
      *
      * Note that optimizations that a compiler will apply to code that is conditional on
      * <code>isCompilationConstant</code> may be limited. For this reason
      * <code>isCompilationConstant</code> is not recommended for use to select between alternate
      * implementations of functionality depending on whether a value is constant. Instead, it is
-     * intended for use as a diagnostic mechanism, such as illustrated above.
+     * intended for use as a diagnostic mechanism.
      *
      * @param value
      * @return {@code true} when given value is seen as compilation constant, {@code false} if not
      *         compilation constant.
      */
     public static boolean isCompilationConstant(Object value) {
-        return false;
+        return CompilerDirectives.inInterpreter();
     }
 
     /**
@@ -203,464 +171,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/TruffleOptions.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleOptions.java	Sat Feb 21 19:55:33 2015 +0100
@@ -38,14 +38,14 @@
      * <p>
      * Can be set with {@code -Dtruffle.ForceInterpreter=true}.
      */
-    public static boolean ForceInterpreter = Boolean.getBoolean("truffle.ForceInterpreter");
+    public static final boolean ForceInterpreter = Boolean.getBoolean("truffle.ForceInterpreter");
 
     /**
      * Enables/disables the rewriting of traces in the Truffle runtime to stdout.
      * <p>
      * Can be set with {@code -Dtruffle.TraceRewrites=true}.
      */
-    public static boolean TraceRewrites;
+    public static final boolean TraceRewrites;
 
     /**
      * Enables the generation of detailed rewrite reasons. Enabling this may introduce some overhead
@@ -97,20 +97,20 @@
     }
 
     static {
-        final boolean[] values = {false, false};
+        final boolean[] values = new boolean[3];
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
             public Void run() {
-                TraceRewrites = Boolean.getBoolean("truffle.TraceRewrites");
+                values[0] = Boolean.getBoolean("truffle.TraceRewrites");
                 TraceRewritesFilterClass = System.getProperty("truffle.TraceRewritesFilterClass");
                 TraceRewritesFilterFromCost = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterFromCost"));
                 TraceRewritesFilterToCost = parseNodeInfoKind(System.getProperty("truffle.TraceRewritesFilterToCost"));
-                values[0] = Boolean.getBoolean("truffle.DetailedRewriteReasons");
-                values[1] = Boolean.getBoolean("truffle.TraceASTJSON");
+                values[1] = Boolean.getBoolean("truffle.DetailedRewriteReasons");
+                values[2] = Boolean.getBoolean("truffle.TraceASTJSON");
                 return null;
             }
         });
-
-        DetailedRewriteReasons = values[0];
-        TraceASTJSON = values[1];
+        TraceRewrites = values[0];
+        DetailedRewriteReasons = values[1];
+        TraceASTJSON = values[2];
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Sat Feb 21 19:55:33 2015 +0100
@@ -33,4 +33,10 @@
     Float,
     Boolean,
     Byte;
+
+    public final byte tag;
+
+    private FrameSlotKind() {
+        this.tag = (byte) ordinal();
+    }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,7 +28,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getObject(FrameSlot)
@@ -44,7 +44,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getByte(FrameSlot)
@@ -60,7 +60,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getBoolean(FrameSlot)
@@ -76,7 +76,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getInt(FrameSlot)
@@ -92,7 +92,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getLong(FrameSlot)
@@ -108,7 +108,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getDouble(FrameSlot)
@@ -124,7 +124,7 @@
     /**
      * Read a frame slot that is guaranteed to be of the desired kind (either previously checked by
      * a guard or statically known).
-     * 
+     *
      * @param frameSlot the slot of the variable
      * @throws IllegalStateException if the slot kind does not match
      * @see Frame#getFloat(FrameSlot)
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultTruffleRuntime.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Sat Feb 21 19:55:33 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;
 
@@ -286,31 +286,31 @@
             return nextInstrument.removeFromChain(instrument);
         }
 
-        public void enter(Node node, VirtualFrame frame) {
-            Instrument.this.toolEventreceiver.enter(node, frame);
+        public void enter(Node node, VirtualFrame vFrame) {
+            Instrument.this.toolEventListener.enter(node, vFrame);
             if (nextInstrument != null) {
-                nextInstrument.enter(node, frame);
+                nextInstrument.enter(node, vFrame);
             }
         }
 
-        public void returnVoid(Node node, VirtualFrame frame) {
-            Instrument.this.toolEventreceiver.returnVoid(node, frame);
+        public void returnVoid(Node node, VirtualFrame vFrame) {
+            Instrument.this.toolEventListener.returnVoid(node, vFrame);
             if (nextInstrument != null) {
-                nextInstrument.returnVoid(node, frame);
+                nextInstrument.returnVoid(node, vFrame);
             }
         }
 
-        public void returnValue(Node node, VirtualFrame frame, Object result) {
-            Instrument.this.toolEventreceiver.returnValue(node, frame, result);
+        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+            Instrument.this.toolEventListener.returnValue(node, vFrame, result);
             if (nextInstrument != null) {
-                nextInstrument.returnValue(node, frame, result);
+                nextInstrument.returnValue(node, vFrame, result);
             }
         }
 
-        public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
-            Instrument.this.toolEventreceiver.returnExceptional(node, frame, exception);
+        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            Instrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
             if (nextInstrument != null) {
-                nextInstrument.returnExceptional(node, frame, exception);
+                nextInstrument.returnExceptional(node, vFrame, 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Sat Feb 21 19:55:33 2015 +0100
@@ -28,6 +28,7 @@
 import java.util.*;
 
 import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.source.*;
 import com.oracle.truffle.api.utilities.*;
@@ -40,7 +41,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>
@@ -80,6 +81,8 @@
      */
     private static final List<WeakReference<Probe>> probes = new ArrayList<>();
 
+    @CompilationFinal private static SyntaxTagTrap tagTrap = null;
+
     private static final class FindSourceVisitor implements NodeVisitor {
 
         Source source = null;
@@ -105,12 +108,6 @@
     }
 
     /**
-     * The tag trap is a global setting; it only affects {@linkplain Probe probes} with the
-     * {@linkplain SyntaxTag tag} specified .
-     */
-    private static SyntaxTagTrap globalTagTrap = null;
-
-    /**
      * Enables instrumentation at selected nodes in all subsequently constructed ASTs.
      */
     public static void registerASTProber(ASTProber prober) {
@@ -156,8 +153,8 @@
     }
 
     /**
-     * Returns all {@link Probe}s holding a particular {@link SyntaxTag}, or the whole collection if
-     * the specified tag is {@code null}.
+     * Returns all {@link Probe}s holding a particular {@link SyntaxTag}, or the whole collection of
+     * probes if the specified tag is {@code null}.
      *
      * @return A collection of probes containing the given tag.
      */
@@ -175,46 +172,22 @@
     }
 
     /**
-     * Sets the current "tag trap". This causes a callback to be triggered whenever execution
-     * reaches a {@link Probe} (either existing or subsequently created) with the specified tag.
-     * There can only be one tag trap set at a time.
+     * Sets the current "tag trap"; there can be no more than one set at a time.
+     * <ul>
+     * <li>A non-null trap sets a callback to be triggered whenever execution reaches a
+     * {@link Probe} (either existing or subsequently created) with the specified tag.</li>
+     * <li>Setting the trap to null clears the existing trap.</li>
+     * <li>Setting a non-null trap when one is already set will clear the previously set trap.</li>
+     * </ul>
      *
      * @param newTagTrap The {@link SyntaxTagTrap} to set.
-     * @throws IllegalStateException if a trap is currently set.
      */
-    public static void setTagTrap(SyntaxTagTrap newTagTrap) throws IllegalStateException {
-        assert newTagTrap != null;
-        if (globalTagTrap != null) {
-            throw new IllegalStateException("trap already set");
-        }
-        globalTagTrap = newTagTrap;
-
-        final SyntaxTag newTag = newTagTrap.getTag();
+    public static void setTagTrap(SyntaxTagTrap newTagTrap) {
+        tagTrap = newTagTrap;
         for (WeakReference<Probe> ref : probes) {
             final Probe probe = ref.get();
-            if (probe != null && probe.tags.contains(newTag)) {
-                probe.trapActive = true;
-                probe.probeStateUnchanged.invalidate();
-            }
-        }
-    }
-
-    /**
-     * Clears the current {@link SyntaxTagTrap}.
-     *
-     * @throws IllegalStateException if no trap is currently set.
-     */
-    public static void clearTagTrap() {
-        if (globalTagTrap == null) {
-            throw new IllegalStateException("no trap set");
-        }
-        globalTagTrap = null;
-
-        for (WeakReference<Probe> ref : probes) {
-            final Probe probe = ref.get();
-            if (probe != null && probe.trapActive) {
-                probe.trapActive = false;
-                probe.probeStateUnchanged.invalidate();
+            if (probe != null) {
+                probe.notifyTrapSet();
             }
         }
     }
@@ -222,12 +195,21 @@
     private final SourceSection sourceSection;
     private final ArrayList<SyntaxTag> tags = new ArrayList<>();
     private final List<WeakReference<ProbeNode>> probeNodeClones = new ArrayList<>();
-    private final CyclicAssumption probeStateUnchanged = new CyclicAssumption("Probe state unchanged");
+
+    /*
+     * Invalidated whenever something changes in the Probe and its Instrument chain, so need deopt
+     */
+    private final CyclicAssumption probeStateUnchangedCyclic = new CyclicAssumption("Probe state unchanged");
 
-    /**
-     * {@code true} iff the global trap is set and this probe has the matching tag.
+    /*
+     * The assumption that nothing had changed in this probe, the last time anybody checked (when
+     * there may have been a deopt). Every time a check fails, gets replaced by a new unchanged
+     * assumption.
      */
-    private boolean trapActive = false;
+    @CompilationFinal private Assumption probeStateUnchangedAssumption = probeStateUnchangedCyclic.getAssumption();
+
+    // Must invalidate whenever this changes.
+    @CompilationFinal private boolean isTrapActive = false;
 
     /**
      * Intended for use only by {@link ProbeNode}.
@@ -261,10 +243,10 @@
             for (ProbeListener listener : probeListeners) {
                 listener.probeTaggedAs(this, tag, tagValue);
             }
-            if (globalTagTrap != null && tag == globalTagTrap.getTag()) {
-                this.trapActive = true;
+            if (tagTrap != null && tag == tagTrap.getTag()) {
+                this.isTrapActive = true;
+                invalidateProbeUnchanged();
             }
-            probeStateUnchanged.invalidate();
         }
     }
 
@@ -288,7 +270,7 @@
                 probeNode.addInstrument(instrument);
             }
         }
-        probeStateUnchanged.invalidate();
+        invalidateProbeUnchanged();
     }
 
     /**
@@ -305,29 +287,6 @@
     }
 
     /**
-     * Receives notification that a new clone of the instrument chain associated with this
-     * {@link Probe} has been created as a side-effect of AST cloning.
-     */
-    void registerProbeNodeClone(ProbeNode probeNode) {
-        probeNodeClones.add(new WeakReference<>(probeNode));
-    }
-
-    /**
-     * Gets the currently active {@linkplain SyntaxTagTrap tagTrap}; {@code null} if not set.
-     */
-    SyntaxTagTrap getTrap() {
-        return trapActive ? globalTagTrap : null;
-    }
-
-    /**
-     * Gets the {@link Assumption} that the instrumentation-related state of this {@link Probe} has
-     * not changed since this method was last called.
-     */
-    Assumption getUnchangedAssumption() {
-        return probeStateUnchanged.getAssumption();
-    }
-
-    /**
      * Internal method for removing and rendering inert a specific instrument previously attached at
      * this Probe.
      *
@@ -342,7 +301,46 @@
                 probeNode.removeInstrument(instrument);
             }
         }
-        probeStateUnchanged.invalidate();
+        invalidateProbeUnchanged();
+    }
+
+    /**
+     * Receives notification that a new clone of the instrument chain associated with this
+     * {@link Probe} has been created as a side-effect of AST cloning.
+     */
+    void registerProbeNodeClone(ProbeNode probeNode) {
+        probeNodeClones.add(new WeakReference<>(probeNode));
+    }
+
+    /**
+     * Gets the currently active {@linkplain SyntaxTagTrap tagTrap}; {@code null} if not set.
+     */
+    SyntaxTagTrap getTrap() {
+        checkProbeUnchanged();
+        return isTrapActive ? tagTrap : null;
+    }
+
+    /**
+     * To be called wherever in the Probe/Instrument chain there are dependencies on the probe
+     * state's @CompilatonFinal fields.
+     */
+    void checkProbeUnchanged() {
+        try {
+            probeStateUnchangedAssumption.check();
+        } catch (InvalidAssumptionException ex) {
+            // Failure creates an implicit deoptimization
+            // Get the assumption associated with the new probe state
+            this.probeStateUnchangedAssumption = probeStateUnchangedCyclic.getAssumption();
+        }
+    }
+
+    private void invalidateProbeUnchanged() {
+        probeStateUnchangedCyclic.invalidate();
+    }
+
+    private void notifyTrapSet() {
+        this.isTrapActive = tagTrap != null && this.isTaggedAs(tagTrap.getTag());
+        invalidateProbeUnchanged();
     }
 
     private String getTagsDescription() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -24,7 +24,6 @@
  */
 package com.oracle.truffle.api.instrument;
 
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.api.frame.*;
@@ -35,7 +34,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 +84,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 +119,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);
     }
 
@@ -176,13 +175,6 @@
         // Never changed once set.
         @CompilationFinal private Probe probe = null;
 
-        /**
-         * An assumption that the state of the {@link Probe} with which this chain is associated has
-         * not changed since the last time checking such an assumption failed and a reference to a
-         * new assumption (associated with a new state of the {@link Probe} was retrieved.
-         */
-        private Assumption probeUnchangedAssumption;
-
         private ProbeFullNode() {
             this.firstInstrument = null;
         }
@@ -201,17 +193,6 @@
 
         private void setProbe(Probe probe) {
             this.probe = probe;
-            this.probeUnchangedAssumption = probe.getUnchangedAssumption();
-        }
-
-        private void checkProbeUnchangedAssumption() {
-            try {
-                probeUnchangedAssumption.check();
-            } catch (InvalidAssumptionException ex) {
-                // Failure creates an implicit deoptimization
-                // Get the assumption associated with the new probe state
-                this.probeUnchangedAssumption = probe.getUnchangedAssumption();
-            }
         }
 
         @Override
@@ -235,57 +216,55 @@
             }
         }
 
-        public void enter(Node node, VirtualFrame frame) {
+        public void enter(Node node, VirtualFrame vFrame) {
+            this.probe.checkProbeUnchanged();
             final SyntaxTagTrap trap = probe.getTrap();
             if (trap != null) {
-                checkProbeUnchangedAssumption();
-                trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), frame.materialize());
+                trap.tagTrappedAt(((WrapperNode) this.getParent()).getChild(), vFrame.materialize());
             }
             if (firstInstrument != null) {
-                checkProbeUnchangedAssumption();
-                firstInstrument.enter(node, frame);
+                firstInstrument.enter(node, vFrame);
             }
         }
 
-        public void returnVoid(Node node, VirtualFrame frame) {
+        public void returnVoid(Node node, VirtualFrame vFrame) {
+            this.probe.checkProbeUnchanged();
             if (firstInstrument != null) {
-                checkProbeUnchangedAssumption();
-                firstInstrument.returnVoid(node, frame);
+                firstInstrument.returnVoid(node, vFrame);
             }
         }
 
-        public void returnValue(Node node, VirtualFrame frame, Object result) {
+        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+            this.probe.checkProbeUnchanged();
             if (firstInstrument != null) {
-                checkProbeUnchangedAssumption();
-                firstInstrument.returnValue(node, frame, result);
+                firstInstrument.returnValue(node, vFrame, result);
             }
         }
 
-        public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
+        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            this.probe.checkProbeUnchanged();
             if (firstInstrument != null) {
-                checkProbeUnchangedAssumption();
-                firstInstrument.returnExceptional(node, frame, exception);
+                firstInstrument.returnExceptional(node, vFrame, exception);
             }
         }
 
         public String instrumentationInfo() {
             return "Standard probe";
         }
-
     }
 
     /**
      * 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
@@ -305,20 +284,20 @@
             throw new IllegalStateException("Instruments may not be removed at a \"lite-probed\" location");
         }
 
-        public void enter(Node node, VirtualFrame frame) {
-            eventReceiver.enter(node, frame);
+        public void enter(Node node, VirtualFrame vFrame) {
+            eventListener.enter(node, vFrame);
         }
 
-        public void returnVoid(Node node, VirtualFrame frame) {
-            eventReceiver.returnVoid(node, frame);
+        public void returnVoid(Node node, VirtualFrame vFrame) {
+            eventListener.returnVoid(node, vFrame);
         }
 
-        public void returnValue(Node node, VirtualFrame frame, Object result) {
-            eventReceiver.returnValue(node, frame, result);
+        public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+            eventListener.returnValue(node, vFrame, result);
         }
 
-        public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
-            eventReceiver.returnExceptional(node, frame, exception);
+        public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+            eventListener.returnExceptional(node, vFrame, exception);
         }
 
         public String instrumentationInfo() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,7 +32,7 @@
  * (for example for mostly expression-oriented languages) or even for specific languages.
  * <p>
  * <strong>Disclaimer:</strong> experimental interface under development.
- * 
+ *
  * @see Probe
  */
 public enum StandardSyntaxTag implements SyntaxTag {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java	Sat Feb 21 19:55:33 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 vFrame);
+
+    /**
+     * Receive notification that an AST Node's {@code void}-valued execute method has just returned.
+     */
+    void returnVoid(Node node, VirtualFrame vFrame);
+
+    /**
+     * Receive notification that an AST Node'sexecute method has just returned a value (boxed if
+     * primitive).
+     */
+    void returnValue(Node node, VirtualFrame vFrame, Object result);
+
+    /**
+     * Receive notification that an AST Node's execute method has just thrown an exception.
+     */
+    void returnExceptional(Node node, VirtualFrame vFrame, Exception exception);
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventReceiver.java	Sat Feb 21 19:47:33 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	Sat Feb 21 19:55:33 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 vFrame) {
+    }
+
+    public void returnVoid(Node node, VirtualFrame vFrame) {
+    }
+
+    public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+    }
+
+    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventReceiver.java	Sat Feb 21 19:47:33 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	Sat Feb 21 19:55:33 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 vFrame) {
+    }
+
+    /**
+     * 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 vFrame
+     */
+    public void returnAny(Node node, VirtualFrame vFrame) {
+    }
+
+    public final void returnVoid(Node node, VirtualFrame vFrame) {
+        returnAny(node, vFrame);
+    }
+
+    public final void returnValue(Node node, VirtualFrame vFrame, Object result) {
+        returnAny(node, vFrame);
+    }
+
+    public final void returnExceptional(Node node, VirtualFrame vFrame, Exception e) {
+        returnAny(node, vFrame);
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventReceiver.java	Sat Feb 21 19:47:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/DirectCallNode.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/IndirectCallNode.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Sat Feb 21 19:55:33 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/nodes/NodeVisitor.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeVisitor.java	Sat Feb 21 19:55:33 2015 +0100
@@ -32,7 +32,7 @@
     /**
      * This visitor method is called for every node in the tree. Its return value determines if the
      * children of this node should be excluded in the iteration.
-     * 
+     *
      * @param node the node that is currently visited
      * @return {@code true} if the children should be visited too, {@code false} otherwise
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -72,7 +72,7 @@
      * language specific implementations may want to return <code>true</code> here to indicate that
      * gathering call site specific profiling information might make sense for this {@link RootNode}
      * .
-     * 
+     *
      * @return <code>true</code> if cloning is allowed else <code>false</code>.
      */
     public boolean isCloningAllowed() {
@@ -91,7 +91,7 @@
 
     /**
      * Executes this function using the specified frame and returns the result value.
-     * 
+     *
      * @param frame the frame of the currently executing guest language method
      * @return the value of the execution
      */
@@ -114,14 +114,14 @@
      * the correct <code>ExecutionContext</code> to be determined for a <code>RootNode</code> (and
      * so also for a {@link RootCallTarget} and a {@link FrameInstance} obtained from the call
      * stack) without prior knowledge of the language it has come from.
-     * 
+     *
      * Used for instance to determine the language of a <code>RootNode<code>:
-     * 
+     *
      * <pre>
      * <code>
      * rootNode.getExecutionContext().getLanguageShortName();
      * </code> </pre>
-     * 
+     *
      * Returns <code>null</code> by default.
      */
     public ExecutionContext getExecutionContext() {
@@ -151,7 +151,7 @@
      * <p>
      * Implementations should ensure that instrumentation is never applied more than once to an AST,
      * as this is not guaranteed to be error-free.
-     * 
+     *
      * @see Probe#registerASTProber(com.oracle.truffle.api.instrument.ASTProber)
      */
     public void applyInstrumentation() {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,7 +39,7 @@
     /**
      * Creates the exception with the alternative result that cannot be represented as a value of
      * the return type.
-     * 
+     *
      * @param result the alternative result
      */
     public UnexpectedResultException(Object result) {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/SerializerConstantPool.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/SerializerConstantPool.java	Sat Feb 21 19:55:33 2015 +0100
@@ -39,7 +39,7 @@
      * additional types that are necessary to serialize a truffle AST for a specific truffle
      * implementation. If a type is not supported by this constant pool implementation a
      * {@link UnsupportedConstantPoolTypeException} should be thrown.
-     * 
+     *
      * @param clazz the {@link Class} of the value
      * @param value the value to be stored. Must be at least a subclass of the given clazz.
      * @return the constant pool index
@@ -54,7 +54,7 @@
      * are necessary to serialize a truffle AST for a specific truffle implementation. If a type is
      * not supported by this constant pool implementation a
      * {@link UnsupportedConstantPoolTypeException} should be thrown.
-     * 
+     *
      * @param clazz the {@link Class} of the value in the constant pool.
      * @param cpi the previously returned index
      * @return the value stored inside the constant pool
@@ -66,7 +66,7 @@
 
     /**
      * Stores a Class instance in the constant pool and returns the constant pool index.
-     * 
+     *
      * @param value the class to store
      * @return the new or existing constant pool index of the Class
      */
@@ -74,7 +74,7 @@
 
     /**
      * Returns the {@link Class} instance to the given constant pool index.
-     * 
+     *
      * @param cpi the constant pool index
      * @return stored value
      * @throws IllegalArgumentException if the constant pool indes is invalid.
@@ -83,7 +83,7 @@
 
     /**
      * Stores an int value in the constant pool and returns the constant pool index.
-     * 
+     *
      * @param value the value to store
      * @return the new or existing constant pool index of the value
      */
@@ -91,7 +91,7 @@
 
     /**
      * Returns the stored int value to the given constant pool index from the constant pool.
-     * 
+     *
      * @param cpi the constant pool index
      * @return stored value
      * @throws IllegalArgumentException if the constant pool index is invalid.
@@ -100,7 +100,7 @@
 
     /**
      * Stores a long value in the constant pool and returns the constant pool index.
-     * 
+     *
      * @param value the value to store
      * @return the new or existing constant pool index of the value
      */
@@ -108,7 +108,7 @@
 
     /**
      * Returns the stored long value to the given constant pool index from the constant pool.
-     * 
+     *
      * @param cpi the constant pool index
      * @return the stored value
      * @throws IllegalArgumentException if the constant pool index is invalid.
@@ -117,7 +117,7 @@
 
     /**
      * Stores a double value in the constant pool and returns the constant pool index.
-     * 
+     *
      * @param value the value to store
      * @return the new or existing constant pool index of the value
      */
@@ -125,7 +125,7 @@
 
     /**
      * Returns the stored double value to the given constant pool index from the constant pool.
-     * 
+     *
      * @param cpi the constant pool index
      * @return the stored value
      * @throws IllegalArgumentException if the constant pool index is invalid.
@@ -134,7 +134,7 @@
 
     /**
      * Stores a float value in the constant pool and returns the constant pool index.
-     * 
+     *
      * @param value the value to store
      * @return the new or existing constant pool index of the value
      */
@@ -142,7 +142,7 @@
 
     /**
      * Returns the stored float value to the given constant pool index from the constant pool.
-     * 
+     *
      * @param cpi the constant pool index
      * @return the stored value
      * @throws IllegalArgumentException if the constant pool index is invalid.
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Sat Feb 21 19:55:33 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,22 +244,21 @@
          */
         private final AtomicLong count;
 
-        CoverageEventReceiver(AtomicLong count) {
+        CoverageEventListener(AtomicLong count) {
             this.count = count;
         }
 
         @Override
-        @TruffleBoundary
-        public void enter(Node node, VirtualFrame frame) {
+        public void enter(Node node, VirtualFrame vFrame) {
             if (isEnabled()) {
                 count.getAndIncrement();
             }
         }
     }
 
-    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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Sat Feb 21 19:55:33 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);
+        public void enter(Node node, VirtualFrame vFrame) {
+            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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,24 +30,24 @@
 /**
  * Abstract utility class to speculate on conditions. Condition profiles are intended to be used as
  * part of if conditions.
- * 
+ *
  * Example usage:
- * 
+ *
  * <pre>
  * private final ConditionProfile zero = ConditionProfile.createBinaryProfile();
- * 
+ *
  * int value = ...;
  * if (zero.profile(value == 0)) {
  *   return 0;
  * } else {
  *   return value;
  * }
- * 
+ *
  * </pre>
- * 
+ *
  * All instances of {@code ConditionProfile} (and subclasses) must be held in {@code final} fields
  * for compiler optimizations to take effect.
- * 
+ *
  * @see #createCountingProfile()
  * @see #createBinaryProfile()
  */
@@ -62,7 +62,7 @@
      * true and false. This information is reported to the underlying optimization system using
      * {@link CompilerDirectives#injectBranchProbability(double, boolean)}. Condition profiles are
      * intended to be used as part of if conditions.
-     * 
+     *
      * @see ConditionProfile
      * @see #createBinaryProfile()
      */
@@ -73,7 +73,7 @@
     /**
      * Returns a {@link ConditionProfile} that speculates on conditions to be never true or to be
      * never false. Condition profiles are intended to be used as part of if conditions.
-     * 
+     *
      * @see ConditionProfile
      * @see ConditionProfile#createCountingProfile()
      */
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Sat Feb 21 19:55:33 2015 +0100
@@ -26,18 +26,18 @@
 
 /**
  * Utility class to speculate on certain properties of values.
- * 
+ *
  * Example usage:
- * 
+ *
  * <pre>
  * private final ValueProfile classProfile = ValueProfile.createClassProfile();
- * 
+ *
  * return classProfile.profile(value);
  * </pre>
- * 
+ *
  * All instances of {@code ValueProfile} (and subclasses) must be held in {@code final} fields for
  * compiler optimizations to take effect.
- * 
+ *
  * @see #createPrimitiveProfile()
  * @see #createIdentityProfile()
  * @see #createClassProfile()
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/TruffleTypes.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,431 @@
+/*
+ * 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 java.util.concurrent.atomic.*;
+
+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 boolean containsComparisons() {
+        final AtomicBoolean found = new AtomicBoolean();
+        this.accept(new AbstractDSLExpressionVisitor() {
+            @Override
+            public void visitBinary(Binary binary) {
+                if (binary.isComparison()) {
+                    found.set(true);
+                }
+            }
+        });
+        return found.get();
+    }
+
+    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;
+        }
+
+        public boolean isComparison() {
+            return DSLExpressionResolver.COMPARABLE_OPERATORS.contains(operator) || DSLExpressionResolver.IDENTITY_OPERATORS.contains(operator);
+        }
+
+        @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	Sat Feb 21 19:55:33 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("||");
+    public static final List<String> COMPARABLE_OPERATORS = Arrays.asList("<", "<=", ">", ">=");
+    public 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/GeneratorUtils.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeFactoryFactory.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java	Sat Feb 21 19:55:33 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));
         }
 
@@ -215,6 +213,8 @@
         }
         clazz.add(createGetCostMethod());
 
+        avoidFindbugsProblems(clazz);
+
         if (singleSpecializable) {
             if (node.needsRewrites(context)) {
                 clazz.add(createUnsupportedMethod());
@@ -238,9 +238,31 @@
         return clazz;
     }
 
+    private void avoidFindbugsProblems(CodeTypeElement clazz) {
+        TypeElement type = context.getEnvironment().getElementUtils().getTypeElement("edu.umd.cs.findbugs.annotations.SuppressFBWarnings");
+        if (type == null) {
+            return;
+        }
+        boolean foundComparison = false;
+        outer: for (SpecializationData specialization : node.getSpecializations()) {
+            for (GuardExpression guard : specialization.getGuards()) {
+                if (guard.getExpression().containsComparisons()) {
+                    foundComparison = true;
+                    break outer;
+                }
+            }
+        }
+
+        if (foundComparison) {
+            CodeAnnotationMirror annotation = new CodeAnnotationMirror((DeclaredType) type.asType());
+            annotation.setElementValue(annotation.findExecutableElement("value"), new CodeAnnotationValue("SA_LOCAL_SELF_COMPARISON"));
+            clazz.addAnnotationMirror(annotation);
+        }
+    }
+
     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 +354,7 @@
 
         List<SpecializationData> generateSpecializations = new ArrayList<>();
         generateSpecializations.add(node.getUninitializedSpecialization());
-        if (needsPolymorphic(reachableSpecializations)) {
+        if (needsPolymorphic()) {
             generateSpecializations.add(node.getPolymorphicSpecialization());
         }
         generateSpecializations.addAll(reachableSpecializations);
@@ -348,6 +370,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 +532,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 +554,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 +600,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 +644,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 +654,7 @@
 
         builder.tree(execution);
 
-        if (hasFallthrough(group, genericType, locals, false)) {
+        if (hasFallthrough(group, genericType, locals, false, null)) {
             builder.returnNull();
         }
         return method;
@@ -711,8 +743,6 @@
         return evaluatedCount;
     }
 
-    // create specialization
-
     private Element createUnsupported() {
         SpecializationData fallback = node.getGenericSpecialization();
         if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) {
@@ -736,12 +766,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 +853,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 +1011,8 @@
                     continue;
                 }
             }
-            builder.string(parameter.getLocalName());
+
+            builder.defaultValue(parameter.getType());
         }
         builder.end();
         return builder.build();
@@ -1012,9 +1056,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 +1108,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 +1142,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 +1154,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 +1242,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 +1338,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 +1422,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 +1467,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 +1479,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 +1505,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 +1523,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 +1574,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 +1618,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 +1657,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 +1675,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 +1688,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 +1696,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 +1722,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 +2124,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 +2258,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 +2294,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 +2506,11 @@
             return values.get(shortCircuitName(execution));
         }
 
+        @Override
+        public String toString() {
+            return "LocalContext [values=" + values + "]";
+        }
+
     }
 
     public static final class LocalVariable {
@@ -2329,6 +2602,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	Sat Feb 21 19:47:33 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	Sat Feb 21 19:47:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/TypeSystemCodeGenerator.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/ElementUtils.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTreeBuilder.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeTypeElement.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/model/CodeVariableElement.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/GuardExpression.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MessageContainer.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/MethodSpec.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeChildData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeExecutionData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/NodeFieldData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/Parameter.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ParameterSpec.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/SpecializationData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TemplateMethod.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/TypeSystemData.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/CreateCastParser.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ExecutableTypeMethodParser.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/MethodSpecParser.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeMethodParser.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java	Sat Feb 21 19:55:33 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,81 +936,196 @@
         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) {
-        if (!node.needsRewrites(context)) {
-            return;
-        }
-
         List<SpecializationData> generics = new ArrayList<>();
         for (SpecializationData spec : node.getSpecializations()) {
             if (spec.isFallback()) {
@@ -1068,10 +1155,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 +1283,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 +1339,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 +1479,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/ShortCircuitParser.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationGroup.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/SpecializationMethodParser.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TemplateMethodParser.java	Sat Feb 21 19:55:33 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.object/src/com/oracle/truffle/object/DynamicObjectImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/DynamicObjectImpl.java	Sat Feb 21 19:55:33 2015 +0100
@@ -30,7 +30,7 @@
 import com.oracle.truffle.object.Locations.ValueLocation;
 import com.oracle.truffle.object.debug.*;
 
-public abstract class DynamicObjectImpl implements DynamicObject, Cloneable {
+public abstract class DynamicObjectImpl extends DynamicObject implements Cloneable {
     private ShapeImpl shape;
 
     public static final DebugCounter reshapeCount = DebugCounter.create("Reshape count");
@@ -49,6 +49,7 @@
         return getShape();
     }
 
+    @Override
     public ShapeImpl getShape() {
         return shape;
     }
@@ -64,6 +65,7 @@
         setShapeAndResize(getShape(), newShape);
     }
 
+    @Override
     public final void setShapeAndResize(Shape oldShape, Shape newShape) {
         assert getShape() == oldShape : "wrong old shape";
         if (oldShape != newShape) {
@@ -81,6 +83,7 @@
      *
      * @see #setShapeAndResize(Shape, Shape)
      */
+    @Override
     public final void setShapeAndGrow(Shape oldShape, Shape newShape) {
         assert getShape() == oldShape : "wrong old shape";
         if (oldShape != newShape) {
@@ -183,6 +186,7 @@
         }
     }
 
+    @Override
     @TruffleBoundary
     public boolean changeFlags(Object id, int newFlags) {
         Shape oldShape = getShape();
@@ -199,6 +203,7 @@
         }
     }
 
+    @Override
     @TruffleBoundary
     public boolean changeFlags(Object id, FlagsFunction updateFunction) {
         Shape oldShape = getShape();
@@ -271,6 +276,7 @@
         return getShape().getObjectType().hashCode(this);
     }
 
+    @Override
     @TruffleBoundary
     public Object get(Object id, Object defaultValue) {
         Property existing = getShape().getProperty(id);
@@ -281,6 +287,7 @@
         }
     }
 
+    @Override
     @TruffleBoundary
     public boolean set(Object id, Object value) {
         Property existing = getShape().getProperty(id);
@@ -292,6 +299,7 @@
         }
     }
 
+    @Override
     @TruffleBoundary
     public void define(Object id, Object value, int flags) {
         ShapeImpl oldShape = getShape();
@@ -318,6 +326,7 @@
         }
     }
 
+    @Override
     @TruffleBoundary
     public void define(Object id, Object value, int flags, LocationFactory locationFactory) {
         ShapeImpl oldShape = getShape();
@@ -333,6 +342,7 @@
         }
     }
 
+    @Override
     @TruffleBoundary
     public boolean delete(Object id) {
         ShapeImpl oldShape = getShape();
@@ -347,14 +357,17 @@
         }
     }
 
+    @Override
     public int size() {
         return getShape().getPropertyCount();
     }
 
+    @Override
     public boolean isEmpty() {
         return size() == 0;
     }
 
+    @Override
     public final boolean updateShape() {
         return getShape().getLayout().getStrategy().updateShape(this);
     }
--- a/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Sat Feb 21 19:55:33 2015 +0100
@@ -275,8 +275,7 @@
      */
     @Override
     @TruffleBoundary
-    public final Property getProperty(Object key) {
-        // return this.propertyMap.get(propertyName);
+    public Property getProperty(Object key) {
         PropertyMap current = this.propertyMap;
         while (current.getLastProperty() != null) {
             if (current.getLastProperty().getKey().equals(key)) {
@@ -284,7 +283,6 @@
             }
             current = current.getParentMap();
         }
-
         return null;
     }
 
--- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/instrument/SLInstrumentTestRunner.java	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLAddNode.java	Sat Feb 21 19:55:33 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/instrument/SLExpressionWrapperNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -84,58 +84,58 @@
     }
 
     @Override
-    public Object executeGeneric(VirtualFrame frame) {
+    public Object executeGeneric(VirtualFrame vFrame) {
 
-        probeNode.enter(child, frame);
+        probeNode.enter(child, vFrame);
         Object result;
 
         try {
-            result = child.executeGeneric(frame);
-            probeNode.returnValue(child, frame, result);
+            result = child.executeGeneric(vFrame);
+            probeNode.returnValue(child, vFrame, result);
         } catch (Exception e) {
-            probeNode.returnExceptional(child, frame, e);
+            probeNode.returnExceptional(child, vFrame, e);
             throw (e);
         }
         return result;
     }
 
     @Override
-    public long executeLong(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectLong(executeGeneric(frame));
+    public long executeLong(VirtualFrame vFrame) throws UnexpectedResultException {
+        return SLTypesGen.expectLong(executeGeneric(vFrame));
     }
 
     @Override
-    public BigInteger executeBigInteger(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectBigInteger(executeGeneric(frame));
+    public BigInteger executeBigInteger(VirtualFrame vFrame) throws UnexpectedResultException {
+        return SLTypesGen.expectBigInteger(executeGeneric(vFrame));
     }
 
     @Override
-    public boolean executeBoolean(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectBoolean(executeGeneric(frame));
+    public boolean executeBoolean(VirtualFrame vFrame) throws UnexpectedResultException {
+        return SLTypesGen.expectBoolean(executeGeneric(vFrame));
     }
 
     @Override
-    public String executeString(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectString(executeGeneric(frame));
+    public String executeString(VirtualFrame vFrame) throws UnexpectedResultException {
+        return SLTypesGen.expectString(executeGeneric(vFrame));
     }
 
     @Override
-    public SLFunction executeFunction(VirtualFrame frame) throws UnexpectedResultException {
-        probeNode.enter(child, frame);
+    public SLFunction executeFunction(VirtualFrame vFrame) throws UnexpectedResultException {
+        probeNode.enter(child, vFrame);
         SLFunction result;
 
         try {
-            result = child.executeFunction(frame);
-            probeNode.returnValue(child, frame, result);
+            result = child.executeFunction(vFrame);
+            probeNode.returnValue(child, vFrame, result);
         } catch (Exception e) {
-            probeNode.returnExceptional(child, frame, e);
+            probeNode.returnExceptional(child, vFrame, e);
             throw (e);
         }
         return result;
     }
 
     @Override
-    public SLNull executeNull(VirtualFrame frame) throws UnexpectedResultException {
-        return SLTypesGen.expectSLNull(executeGeneric(frame));
+    public SLNull executeNull(VirtualFrame vFrame) throws UnexpectedResultException {
+        return SLTypesGen.expectSLNull(executeGeneric(vFrame));
     }
 }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Sat Feb 21 19:55:33 2015 +0100
@@ -78,16 +78,16 @@
     }
 
     @Override
-    public void executeVoid(VirtualFrame frame) {
-        probeNode.enter(child, frame);
+    public void executeVoid(VirtualFrame vFrame) {
+        probeNode.enter(child, vFrame);
 
         try {
-            child.executeVoid(frame);
-            probeNode.returnVoid(child, frame);
+            child.executeVoid(vFrame);
+            probeNode.returnVoid(child, vFrame);
         } catch (KillException e) {
             throw (e);
         } catch (Exception e) {
-            probeNode.returnExceptional(child, frame, e);
+            probeNode.returnExceptional(child, vFrame, e);
             throw (e);
         }
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java	Sat Feb 21 19:47:33 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/local/SLWriteLocalVariableNode.java	Sat Feb 21 19:55:33 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/hotspot/.cproject	Sat Feb 21 19:47:33 2015 +0100
+++ b/hotspot/.cproject	Sat Feb 21 19:55:33 2015 +0100
@@ -45,7 +45,6 @@
 									<listOptionValue builtIn="false" value="GRAAL=1"/>
 									<listOptionValue builtIn="false" value="COMPILER2=1"/>
 									<listOptionValue builtIn="false" value="COMPILERGRAAL=1"/>
-									<listOptionValue builtIn="false" value="GRAALVM=1"/>
 								</option>
 								<option id="gnu.cpp.compiler.option.preprocessor.undef.2137486146" name="Undefined symbols (-U)" superClass="gnu.cpp.compiler.option.preprocessor.undef"/>
 								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.866181452" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
@@ -84,11 +83,415 @@
 			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
 			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
 		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162" moduleId="org.eclipse.cdt.core.settings" name="Server">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="hotspot" buildProperties="" description="Server VM with graal enabled (Tiered)" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162" name="Server" parent="org.eclipse.cdt.build.core.emptycfg">
+					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.base.1741231788" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.1058861512" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build --no-java" autoBuildTarget="" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.1971483913" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
+								<outputEntries>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
+								</outputEntries>
+							</builder>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.446231503" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.677873708" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+								<option id="gnu.cpp.compiler.option.include.paths.2060190160" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.def.270375031" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+									<listOptionValue builtIn="false" value="LINUX=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_COMPILER_gcc=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_FAMILY_linux=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_ARCH_linux_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_MODEL_x86_64=1"/>
+									<listOptionValue builtIn="false" value="GRAAL=1"/>
+									<listOptionValue builtIn="false" value="COMPILER2=1"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.undef.553556482" name="Undefined symbols (-U)" superClass="gnu.cpp.compiler.option.preprocessor.undef"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.429177901" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1536145259" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.664112776" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1935913022" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.base.190805864" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.661896739" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1889460576" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.base.770549769" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.2130492397" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162" moduleId="org.eclipse.cdt.core.settings" name="Client">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="hotspot" buildProperties="" description="Client VM with Graal enabled" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162" name="Client" parent="org.eclipse.cdt.build.core.emptycfg">
+					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.base.1944635494" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.760397453" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build --no-java" autoBuildTarget="" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.2024267298" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
+								<outputEntries>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
+								</outputEntries>
+							</builder>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.805698881" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1673917487" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+								<option id="gnu.cpp.compiler.option.include.paths.1395828869" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.def.1699174802" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+									<listOptionValue builtIn="false" value="LINUX=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_COMPILER_gcc=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_FAMILY_linux=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_ARCH_linux_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_MODEL_x86_64=1"/>
+									<listOptionValue builtIn="false" value="GRAAL=1"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.undef.2019710410" name="Undefined symbols (-U)" superClass="gnu.cpp.compiler.option.preprocessor.undef"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.931461388" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.1862778408" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.327213605" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.29080811" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.base.499906465" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.367432319" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1206523880" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.base.43198633" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.757957452" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp|shared/vm/opto" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004" moduleId="org.eclipse.cdt.core.settings" name="Graal">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="hotspot" buildProperties="" description="Graal VM (Tiered)" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004" name="Graal" parent="org.eclipse.cdt.build.core.emptycfg">
+					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.base.1790873354" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.2087199731" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build --no-java" autoBuildTarget="" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.1107701476" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
+								<outputEntries>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
+								</outputEntries>
+							</builder>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.111821059" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.501581878" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+								<option id="gnu.cpp.compiler.option.include.paths.1285141101" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.def.1301765451" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+									<listOptionValue builtIn="false" value="LINUX=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_COMPILER_gcc=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_FAMILY_linux=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_ARCH_linux_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_MODEL_x86_64=1"/>
+									<listOptionValue builtIn="false" value="GRAAL=1"/>
+									<listOptionValue builtIn="false" value="COMPILERGRAAL=1"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.undef.1682796822" name="Undefined symbols (-U)" superClass="gnu.cpp.compiler.option.preprocessor.undef"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1552002453" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.647707969" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.824582057" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1613323394" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1066932337" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.23923928" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.92649386" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.base.856169124" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.1667718151" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051" moduleId="org.eclipse.cdt.core.settings" name="Server no Graal">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="hotspot" buildProperties="" description="Server VM without Graal extentions (Tiered)" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051" name="Server no Graal" parent="org.eclipse.cdt.build.core.emptycfg">
+					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.base.264813073" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.555589372" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build --no-java" autoBuildTarget="" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.1661210962" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
+								<outputEntries>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
+								</outputEntries>
+							</builder>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.832885832" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1920567990" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+								<option id="gnu.cpp.compiler.option.include.paths.839069865" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.def.1804264717" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+									<listOptionValue builtIn="false" value="LINUX=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_COMPILER_gcc=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_FAMILY_linux=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_ARCH_linux_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_MODEL_x86_64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER2=1"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.undef.438887425" name="Undefined symbols (-U)" superClass="gnu.cpp.compiler.option.preprocessor.undef"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1463421641" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.592469102" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.829508688" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1891927256" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.base.349030735" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.1778058716" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1044422632" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.base.967152326" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.983789158" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+		</cconfiguration>
+		<cconfiguration id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225">
+			<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225" moduleId="org.eclipse.cdt.core.settings" name="Client no Graal">
+				<externalSettings/>
+				<extensions>
+					<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+					<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+					<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+				</extensions>
+			</storageModule>
+			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+				<configuration artifactName="hotspot" buildProperties="" description="Client VM without Graal extentions" id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225" name="Client no Graal" parent="org.eclipse.cdt.build.core.emptycfg">
+					<folderInfo id="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225." name="/" resourcePath="">
+						<toolChain id="cdt.managedbuild.toolchain.gnu.base.237868264" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.base">
+							<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.target.gnu.platform.base.819675926" name="Debug Platform" osList="linux,hpux,aix,qnx" superClass="cdt.managedbuild.target.gnu.platform.base"/>
+							<builder arguments="${workspace_loc:/hotspot}/../mxtool/mx build --no-java" autoBuildTarget="" buildPath="${workspace_loc:/hotspot}/.." cleanBuildTarget="clean" command="bash" enableAutoBuild="true" enableCleanBuild="false" enabledIncrementalBuild="false" id="cdt.managedbuild.target.gnu.builder.base.1052794537" incrementalBuildTarget="jvmg1" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="cdt.managedbuild.target.gnu.builder.base">
+								<outputEntries>
+									<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="outputPath" name=""/>
+								</outputEntries>
+							</builder>
+							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1406128591" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.base.1404788740" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.base">
+								<option id="gnu.cpp.compiler.option.include.paths.701589205" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
+									<listOptionValue builtIn="false" value="&quot;${workspace_loc:/com.oracle.graal.hotspot/src_gen/hotspot}&quot;"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.def.815907884" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+									<listOptionValue builtIn="false" value="LINUX=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_COMPILER_gcc=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_FAMILY_linux=1"/>
+									<listOptionValue builtIn="false" value="TARGET_OS_ARCH_linux_x86=1"/>
+									<listOptionValue builtIn="false" value="TARGET_ARCH_MODEL_x86_64=1"/>
+								</option>
+								<option id="gnu.cpp.compiler.option.preprocessor.undef.1580814100" name="Undefined symbols (-U)" superClass="gnu.cpp.compiler.option.preprocessor.undef"/>
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1175382997" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.compiler.base.961579870" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.base">
+								<option id="gnu.c.compiler.option.preprocessor.def.symbols.1147358177" name="Defined symbols (-D)" superClass="gnu.c.compiler.option.preprocessor.def.symbols" valueType="definedSymbols">
+									<listOptionValue builtIn="false" value="_LP64=1"/>
+									<listOptionValue builtIn="false" value="COMPILER1=1"/>
+									<listOptionValue builtIn="false" value="VM_LITTLE_ENDIAN=1"/>
+									<listOptionValue builtIn="false" value="ASSERT=1"/>
+									<listOptionValue builtIn="false" value="_REENTRANT=1"/>
+									<listOptionValue builtIn="false" value="DEBUG=1"/>
+									<listOptionValue builtIn="false" value="AMD64=1"/>
+								</option>
+								<inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.1710196852" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.c.linker.base.1903854315" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.base"/>
+							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.base.496829534" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.base">
+								<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1852502664" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+									<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+									<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+								</inputType>
+							</tool>
+							<tool id="cdt.managedbuild.tool.gnu.assembler.base.2132345407" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.base">
+								<inputType id="cdt.managedbuild.tool.gnu.assembler.input.140899416" superClass="cdt.managedbuild.tool.gnu.assembler.input"/>
+							</tool>
+						</toolChain>
+					</folderInfo>
+					<sourceEntries>
+						<entry excluding="cpu/vm/templateTable_x86_32.cpp|cpu/vm/templateInterpreter_x86_32.cpp|cpu/vm/stubRoutines_x86_32.cpp|cpu/vm/stubGenerator_x86_32.cpp|cpu/vm/sharedRuntime_x86_32.cpp|cpu/vm/jniFastGetField_x86_32.cpp|cpu/vm/interpreterRT_x86_32.cpp|cpu/vm/interpreter_x86_32.cpp|cpu/vm/interp_masm_x86_32.cpp|cpu/vm/vtableStubs_x86_32.cpp|shared/vm/opto|shared/vm/graal" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
+					</sourceEntries>
+				</configuration>
+			</storageModule>
+			<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+			<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+			<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
+			<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"/>
+		</cconfiguration>
 	</storageModule>
 	<storageModule moduleId="cdtBuildSystem" version="4.0.0">
 		<project id="hotspot.null.1712822257" name="hotspot"/>
 	</storageModule>
 	<storageModule moduleId="refreshScope" versionNumber="2">
+		<configuration configurationName="Client">
+			<resource resourceType="PROJECT" workspacePath="/hotspot"/>
+		</configuration>
 		<configuration configurationName="Default">
 			<resource resourceType="PROJECT" workspacePath="/hotspot"/>
 		</configuration>
@@ -97,23 +500,53 @@
 	<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
 	<storageModule moduleId="scannerConfiguration">
 		<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162.;cdt.managedbuild.tool.gnu.c.compiler.base.1862778408;cdt.managedbuild.tool.gnu.c.compiler.input.29080811">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004.;cdt.managedbuild.tool.gnu.cpp.compiler.base.501581878;cdt.managedbuild.tool.gnu.cpp.compiler.input.1552002453">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.388217325;cdt.managedbuild.tool.gnu.solaris.cpp.compiler.base.377383651;cdt.managedbuild.tool.gnu.cpp.compiler.input.103897085">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 		</scannerConfigBuildInfo>
-		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.solaris.cpp.compiler.base.429326045;cdt.managedbuild.tool.gnu.cpp.compiler.input.1860785837">
-			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.solaris.c.compiler.base.351149667;cdt.managedbuild.tool.gnu.c.compiler.input.820447325">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.388217325;cdt.managedbuild.tool.gnu.solaris.c.compiler.base.212558466;cdt.managedbuild.tool.gnu.c.compiler.input.1115218695">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
-		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057;cdt.managedbuild.tool.gnu.cpp.compiler.input.866181452">
-			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
-		</scannerConfigBuildInfo>
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.c.compiler.base.1535888880;cdt.managedbuild.tool.gnu.c.compiler.input.906671119">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
-		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.solaris.c.compiler.base.351149667;cdt.managedbuild.tool.gnu.c.compiler.input.820447325">
-			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051.;cdt.managedbuild.tool.gnu.c.compiler.base.592469102;cdt.managedbuild.tool.gnu.c.compiler.input.1891927256">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.solaris.cpp.compiler.base.429326045;cdt.managedbuild.tool.gnu.cpp.compiler.input.1860785837">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004.;cdt.managedbuild.tool.gnu.c.compiler.base.647707969;cdt.managedbuild.tool.gnu.c.compiler.input.1613323394">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162.;cdt.managedbuild.tool.gnu.c.compiler.base.1536145259;cdt.managedbuild.tool.gnu.c.compiler.input.1935913022">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.305678577;cdt.managedbuild.tool.gnu.cpp.compiler.base.1342888057;cdt.managedbuild.tool.gnu.cpp.compiler.input.866181452">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225.;cdt.managedbuild.tool.gnu.cpp.compiler.base.1404788740;cdt.managedbuild.tool.gnu.cpp.compiler.input.1175382997">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162.;cdt.managedbuild.tool.gnu.cpp.compiler.base.677873708;cdt.managedbuild.tool.gnu.cpp.compiler.input.429177901">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051.;cdt.managedbuild.tool.gnu.cpp.compiler.base.1920567990;cdt.managedbuild.tool.gnu.cpp.compiler.input.1463421641">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225.;cdt.managedbuild.tool.gnu.c.compiler.base.961579870;cdt.managedbuild.tool.gnu.c.compiler.input.1710196852">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162;cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162.;cdt.managedbuild.tool.gnu.cpp.compiler.base.1673917487;cdt.managedbuild.tool.gnu.cpp.compiler.input.931461388">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
 		</scannerConfigBuildInfo>
 	</storageModule>
 </cproject>
--- a/hotspot/.settings/org.eclipse.cdt.core.prefs	Sat Feb 21 19:47:33 2015 +0100
+++ b/hotspot/.settings/org.eclipse.cdt.core.prefs	Sat Feb 21 19:55:33 2015 +0100
@@ -1,4 +1,29 @@
 eclipse.preferences.version=1
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162/BUILDING_FROM_IDE/delimiter=\:
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162/BUILDING_FROM_IDE/operation=append
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162/BUILDING_FROM_IDE/value=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162/append=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.1958236162/appendContributed=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004/BUILDING_FROM_IDE/delimiter=\:
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004/BUILDING_FROM_IDE/operation=append
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004/BUILDING_FROM_IDE/value=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004/append=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.2116626004/appendContributed=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051/BUILDING_FROM_IDE/delimiter=\:
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051/BUILDING_FROM_IDE/operation=append
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051/BUILDING_FROM_IDE/value=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051/append=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.500153051/appendContributed=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225/BUILDING_FROM_IDE/delimiter=\:
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225/BUILDING_FROM_IDE/operation=append
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225/BUILDING_FROM_IDE/value=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225/append=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.915924225/appendContributed=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162/BUILDING_FROM_IDE/delimiter=\:
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162/BUILDING_FROM_IDE/operation=append
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162/BUILDING_FROM_IDE/value=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162/append=true
+environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881.982312162/appendContributed=true
 environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881/BUILDING_FROM_IDE/delimiter=\:
 environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881/BUILDING_FROM_IDE/operation=append
 environment/project/cdt.managedbuild.toolchain.gnu.solaris.base.945602881/BUILDING_FROM_IDE/value=true
@@ -28,6 +53,7 @@
 org.eclipse.cdt.core.formatter.brace_position_for_switch=end_of_line
 org.eclipse.cdt.core.formatter.brace_position_for_type_declaration=end_of_line
 org.eclipse.cdt.core.formatter.comment.min_distance_between_code_and_line_comment=1
+org.eclipse.cdt.core.formatter.comment.never_indent_line_comments_on_first_column=true
 org.eclipse.cdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
 org.eclipse.cdt.core.formatter.compact_else_if=true
 org.eclipse.cdt.core.formatter.continuation_indentation=2
--- a/mx/eclipse-settings/org.eclipse.jdt.core.prefs	Sat Feb 21 19:47:33 2015 +0100
+++ b/mx/eclipse-settings/org.eclipse.jdt.core.prefs	Sat Feb 21 19:55:33 2015 +0100
@@ -45,7 +45,7 @@
 org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
 org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
 org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
 org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
 org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=ignore
 org.eclipse.jdt.core.compiler.problem.forbiddenReference=ignore
--- a/mx/mx_graal.py	Sat Feb 21 19:47:33 2015 +0100
+++ b/mx/mx_graal.py	Sat Feb 21 19:55:33 2015 +0100
@@ -1490,11 +1490,6 @@
         with Task('UnitTests:hosted-product', tasks):
             unittest(['--enable-timing', '--verbose', '--fail-fast'])
 
-    # Run baseline unit tests on server-hosted-graal
-    with VM('server', 'product'):
-        with Task('UnitTests-BaselineCompiler:hosted-product', tasks):
-            unittest(['--enable-timing', '--verbose', '--whitelist', 'test/whitelist_baseline.txt', '-G:+UseBaselineCompiler'])
-
     # Build the other VM flavors
     with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks):
         buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
@@ -1722,14 +1717,19 @@
 
         # Remove NetBeans platform if it is earlier than the current supported version
         if exists(nbplatform):
-            dom = xml.dom.minidom.parse(join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml'))
-            currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version'))
-            supportedVersion = mx.VersionSpec('3.43.1')
-            if currentVersion < supportedVersion:
-                mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion))
+            updateTrackingFile = join(nbplatform, 'platform', 'update_tracking', 'org-netbeans-core.xml')
+            if not exists(updateTrackingFile):
+                mx.log('Could not find \'' + updateTrackingFile + '\', removing NetBeans platform')
                 shutil.rmtree(nbplatform)
-            elif supportedVersion < currentVersion:
-                mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion))
+            else:
+                dom = xml.dom.minidom.parse(updateTrackingFile)
+                currentVersion = mx.VersionSpec(dom.getElementsByTagName('module_version')[0].getAttribute('specification_version'))
+                supportedVersion = mx.VersionSpec('3.43.1')
+                if currentVersion < supportedVersion:
+                    mx.log('Replacing NetBeans platform version ' + str(currentVersion) + ' with version ' + str(supportedVersion))
+                    shutil.rmtree(nbplatform)
+                elif supportedVersion < currentVersion:
+                    mx.log('Supported NetBeans version in igv command should be updated to ' + str(currentVersion))
 
         if not exists(nbplatform):
             mx.logv('[This execution may take a while as the NetBeans platform needs to be downloaded]')
--- a/mx/suite.py	Sat Feb 21 19:47:33 2015 +0100
+++ b/mx/suite.py	Sat Feb 21 19:55:33 2015 +0100
@@ -343,7 +343,6 @@
         "com.oracle.graal.replacements",
         "com.oracle.graal.runtime",
         "com.oracle.graal.printer",
-        "com.oracle.graal.baseline",
         "com.oracle.graal.hotspotvmconfig",
         "com.oracle.nfi",
       ],
@@ -592,6 +591,7 @@
       "dependencies" : [
         "com.oracle.graal.compiler",
         "com.oracle.graal.java",
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.word",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -802,7 +802,6 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.graal.api.directives",
         "com.oracle.graal.phases",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -824,18 +823,6 @@
       "workingSets" : "Graal,Java",
     },
 
-    "com.oracle.graal.baseline" : {
-      "subDir" : "graal",
-      "sourceDirs" : ["src"],
-      "dependencies" : [
-        "com.oracle.graal.compiler",
-        "com.oracle.graal.java",
-      ],
-      "checkstyle" : "com.oracle.graal.graph",
-      "javaCompliance" : "1.8",
-      "workingSets" : "Graal,Java",
-    },
-
     "com.oracle.graal.printer" : {
       "subDir" : "graal",
       "sourceDirs" : ["src"],
@@ -864,10 +851,10 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.test",
         "com.oracle.graal.printer",
         "com.oracle.graal.runtime",
-        "com.oracle.graal.baseline",
         "JAVA_ALLOCATION_INSTRUMENTER",
       ],
       "checkstyle" : "com.oracle.graal.graph",
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Sat Feb 21 19:55:33 2015 +0100
@@ -3521,6 +3521,9 @@
   //__ add(G0, 0x321, O7);
   __ add(O7, -8, O7);
   //__ st_ptr(I7, SP, I7->sp_offset_in_saved_window()*wordSize + STACK_BIAS);
+
+  int uncommon_trap_offset = __ offset() - start;
+
   // Save everything in sight.
   masm->block_comment("save_live_regs");
   (void) RegisterSaver::save_live_registers(masm, 0, &frame_size_words);
@@ -3729,6 +3732,7 @@
   _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_words);
   _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
 #ifdef GRAAL
+  _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
   _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
 #endif
 }
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Sat Feb 21 19:55:33 2015 +0100
@@ -3409,6 +3409,8 @@
 
   __ pushptr(Address(r15_thread, in_bytes(JavaThread::graal_implicit_exception_pc_offset())));
 
+  int uncommon_trap_offset = __ pc() - start;
+
   // Save everything in sight.
   RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words);
   // fetch_unroll_info needs to call last_java_frame()
@@ -3692,6 +3694,7 @@
   _deopt_blob = DeoptimizationBlob::create(&buffer, oop_maps, 0, exception_offset, reexecute_offset, frame_size_in_words);
   _deopt_blob->set_unpack_with_exception_in_tls_offset(exception_in_tls_offset);
 #ifdef GRAAL
+  _deopt_blob->set_uncommon_trap_offset(uncommon_trap_offset);
   _deopt_blob->set_implicit_exception_uncommon_trap_offset(implicit_exception_uncommon_trap_offset);
 #endif
 }
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/layer.xml	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/layer.xml	Sat Feb 21 19:55:33 2015 +0100
@@ -67,7 +67,7 @@
         <folder name="Nodes">
             <attr name="command" stringvalue="n"/>
             <attr name="position" intvalue="0"/>
-            <file name="com-sun-hotspot-igv-view-NodeQuickSearch.instance" />
+            <file name="com-sun-hotspot-igv-view-NodeQuickSearch.instance"/>
         </folder>
     </folder>
     
@@ -77,4 +77,12 @@
             
         </file>    
     </folder>
+    <folder name="Windows2">
+        <folder name="Modes">
+            <folder name="properties">
+                <file name="properties.wstcref" url="propertiesWstcref.xml"/>
+            </folder>
+            <file name="properties.wsmode" url="propertiesWsmode.xml"/>
+        </folder>
+    </folder>
 </filesystem>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/propertiesWsmode.xml	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE mode PUBLIC
+          "-//NetBeans//DTD Mode Properties 2.0//EN"
+          "http://www.netbeans.org/dtds/mode-properties2_0.dtd">
+
+<mode version="2.0">
+    <name unique="properties" />
+    <kind type="view" />
+    <state type="joined" />
+    <constraints>
+        <path orientation="horizontal" number="90" weight="0.2"/>
+        <path orientation="vertical" number="1" weight="0.50"/>
+    </constraints>
+    <relative-bounds x="75" y="56" width="15" height="32" />
+    <active-tc id="properties" />
+    <empty-behavior permanent="true" />
+</mode>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/propertiesWstcref.xml	Sat Feb 21 19:55:33 2015 +0100
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE tc-ref PUBLIC
+          "-//NetBeans//DTD Top Component in Mode Properties 2.0//EN"
+          "http://www.netbeans.org/dtds/tc-ref2_0.dtd">
+
+<tc-ref version="2.0">
+    <module name="org.netbeans.core.ui/1" spec="1.2" />
+    <tc-id id="properties" />
+    <state opened="true" />
+</tc-ref>
--- a/src/share/vm/classfile/classFileParser.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/classfile/classFileParser.cpp	Sat Feb 21 19:55:33 2015 +0100
@@ -4147,6 +4147,10 @@
         tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
                    InstanceKlass::cast(class_loader->klass())->external_name());
       }
+      if (WizardMode) {
+        // useful when investigating why a class is loaded
+        JavaThread::current()->print_stack_on(tty);
+      }
     }
 
     if (TraceClassResolution) {
--- a/src/share/vm/classfile/systemDictionary.hpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Sat Feb 21 19:55:33 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/code/codeBlob.hpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/code/codeBlob.hpp	Sat Feb 21 19:55:33 2015 +0100
@@ -358,6 +358,8 @@
   int _unpack_with_exception_in_tls;
 
 #ifdef GRAAL
+  // (thomaswue) Offset when Graal calls uncommon_trap.
+  int _uncommon_trap_offset;
   int _implicit_exception_uncommon_trap_offset;
 #endif
 
@@ -415,6 +417,13 @@
   address unpack_with_exception_in_tls() const   { return code_begin() + _unpack_with_exception_in_tls; }
 
 #ifdef GRAAL
+  // (thomaswue) Offset when Graal calls uncommon_trap.
+  void set_uncommon_trap_offset(int offset) {
+    _uncommon_trap_offset = offset;
+    assert(contains(code_begin() + _uncommon_trap_offset), "must be PC inside codeblob");
+  }
+  address uncommon_trap() const                  { return code_begin() + _uncommon_trap_offset;     }
+
   void set_implicit_exception_uncommon_trap_offset(int offset) {
     _implicit_exception_uncommon_trap_offset = offset;
     assert(contains(code_begin() + _implicit_exception_uncommon_trap_offset), "must be PC inside codeblob");
--- a/src/share/vm/code/dependencies.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/code/dependencies.cpp	Sat Feb 21 19:55:33 2015 +0100
@@ -737,10 +737,10 @@
 }
 
 void Dependencies::print_dependency(DepType dept, int nargs, DepArgument args[],
-                                    Klass* witness) {
+                                    Klass* witness, outputStream* st) {
   ResourceMark rm;
   ttyLocker ttyl;   // keep the following output all in one block
-  tty->print_cr("%s of type %s",
+  st->print_cr("%s of type %s",
                 (witness == NULL)? "Dependency": "Failed dependency",
                 dep_name(dept));
   // print arguments
@@ -762,18 +762,18 @@
     } else {
       what = "object ";
     }
-    tty->print("  %s = %s", what, (put_star? "*": ""));
+    st->print("  %s = %s", what, (put_star? "*": ""));
     if (arg.is_klass())
-      tty->print("%s", ((Klass*)arg.metadata_value())->external_name());
+      st->print("%s", ((Klass*)arg.metadata_value())->external_name());
     else if (arg.is_method())
-      ((Method*)arg.metadata_value())->print_value();
+      ((Method*)arg.metadata_value())->print_value_on(st);
     else
       ShouldNotReachHere(); // Provide impl for this type.
-    tty->cr();
+    st->cr();
   }
   if (witness != NULL) {
     bool put_star = !Dependencies::is_concrete_klass(witness);
-    tty->print_cr("  witness = %s%s",
+    st->print_cr("  witness = %s%s",
                   (put_star? "*": ""),
                   witness->external_name());
   }
@@ -806,18 +806,18 @@
   }
 }
 
-void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) {
+void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose, outputStream* st) {
   int nargs = argument_count();
   DepArgument args[max_arg_count];
   for (int j = 0; j < nargs; j++) {
     args[j] = argument(j);
   }
-  Dependencies::print_dependency(type(), nargs, args, witness);
+  Dependencies::print_dependency(type(), nargs, args, witness, st);
   if (verbose) {
     if (_code != NULL) {
-      tty->print("  code: ");
-      _code->print_value_on(tty);
-      tty->cr();
+      st->print("  code: ");
+      _code->print_value_on(st);
+      st->cr();
     }
   }
 }
--- a/src/share/vm/code/dependencies.hpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/code/dependencies.hpp	Sat Feb 21 19:55:33 2015 +0100
@@ -508,7 +508,7 @@
                                   Klass* witness = NULL);
   static void print_dependency(DepType dept,
                                int nargs, DepArgument args[],
-                               Klass* witness = NULL);
+                               Klass* witness = NULL, outputStream* st = tty);
 
  private:
   // helper for encoding common context types as zero:
@@ -605,7 +605,7 @@
     void log_dependency(Klass* witness = NULL);
 
     // Print the current dependency to tty.
-    void print_dependency(Klass* witness = NULL, bool verbose = false);
+    void print_dependency(Klass* witness = NULL, bool verbose = false, outputStream* st = tty);
   };
   friend class Dependencies::DepStream;
 
--- a/src/share/vm/compiler/compileBroker.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Sat Feb 21 19:55:33 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, compiled_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	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Sat Feb 21 19:55:33 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	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.hpp	Sat Feb 21 19:55:33 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/graalCompilerToVM.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Sat Feb 21 19:55:33 2015 +0100
@@ -240,13 +240,40 @@
   class_loader = accessing_klass->class_loader();
   protection_domain = accessing_klass->protection_domain();
 
-
   if (resolve) {
-    resolved_klass = SystemDictionary::resolve_or_fail(class_name, class_loader, protection_domain, true, THREAD);
+    resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, CHECK_0);
   } else {
-    resolved_klass = SystemDictionary::resolve_or_null(class_name, class_loader, protection_domain, THREAD);
+    if (class_name->byte_at(0) == 'L' &&
+      class_name->byte_at(class_name->utf8_length()-1) == ';') {
+      // This is a name from a signature.  Strip off the trimmings.
+      // Call recursive to keep scope of strippedsym.
+      TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1,
+                                                          class_name->utf8_length()-2,
+                                                          CHECK_0);
+      resolved_klass = SystemDictionary::find(strippedsym, class_loader, protection_domain, CHECK_0);
+    } else if (FieldType::is_array(class_name)) {
+      FieldArrayInfo fd;
+      // dimension and object_key in FieldArrayInfo are assigned as a side-effect
+      // of this call
+      BasicType t = FieldType::get_array_info(class_name, fd, CHECK_0);
+      if (t == T_OBJECT) {
+        TempNewSymbol strippedsym = SymbolTable::new_symbol(class_name->as_utf8()+1+fd.dimension(),
+                                                            class_name->utf8_length()-2-fd.dimension(),
+                                                            CHECK_0);
+        // naked oop "k" is OK here -- we assign back into it
+        resolved_klass = SystemDictionary::find(strippedsym,
+                                                             class_loader,
+                                                             protection_domain,
+                                                             CHECK_0);
+        if (resolved_klass != NULL) {
+          resolved_klass = resolved_klass->array_klass(fd.dimension(), CHECK_0);
+        }
+      } else {
+        resolved_klass = Universe::typeArrayKlassObj(t);
+        resolved_klass = TypeArrayKlass::cast(resolved_klass)->array_klass(fd.dimension(), CHECK_0);
+      }
+    }
   }
-
   return (jlong) (address) resolved_klass;
 C2V_END
 
--- a/src/share/vm/graal/graalEnv.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalEnv.cpp	Sat Feb 21 19:55:33 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,23 +421,33 @@
 // ------------------------------------------------------------------
 // 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, Handle compiled_code, GraalEnv* env, char** failure_detail) {
+  // 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()) {
+      *failure_detail = (char*) "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();
+    Klass* witness = deps.check_dependency();
     if (witness != NULL) {
+      // Use a fixed size buffer to prevent the string stream from
+      // resizing in the context of an inner resource mark.
+      char* buffer = NEW_RESOURCE_ARRAY(char, O_BUFLEN);
+      stringStream st(buffer, O_BUFLEN);
+      deps.print_dependency(witness, true, &st);
+      *failure_detail = st.as_string();
       return false;
     }
     if (LogCompilation) {
@@ -450,15 +472,18 @@
                                 AbstractCompiler* compiler,
                                 DebugInformationRecorder* debug_info,
                                 Dependencies* dependencies,
-                                CompileTask* task,
+                                GraalEnv* env,
                                 int compile_id,
                                 bool has_unsafe_access,
                                 Handle installed_code,
+                                Handle compiled_code,
                                 Handle speculation_log) {
   GRAAL_EXCEPTION_CONTEXT;
   NMethodSweeper::possibly_sweep();
   nm = NULL;
   int comp_level = CompLevel_full_optimization;
+  char* failure_detail = NULL;
+  GraalEnv::CodeInstallResult result;
   {
     // To prevent compile queue updates.
     MutexLocker locker(MethodCompileQueue_lock, THREAD);
@@ -471,7 +496,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, compiled_code, env, &failure_detail)) {
       // While not a true deoptimization, it is a preemptive decompile.
       MethodData* mdp = method()->method_data();
       if (mdp != NULL) {
@@ -488,82 +513,91 @@
       // If the code buffer is created on each compile attempt
       // as in C2, then it must be freed.
       //code_buffer->free_blob();
-      return GraalEnv::dependencies_failed;
-    }
-    ImplicitExceptionTable implicit_tbl;
-    nm =  nmethod::new_nmethod(method,
-                               compile_id,
-                               entry_bci,
-                               offsets,
-                               orig_pc_offset,
-                               debug_info, dependencies, code_buffer,
-                               frame_words, oop_map_set,
-                               handler_table, &implicit_tbl,
-                               compiler, comp_level, installed_code, speculation_log);
+      result = GraalEnv::dependencies_failed;
+    } else {
+      ImplicitExceptionTable implicit_tbl;
+      nm =  nmethod::new_nmethod(method,
+                                 compile_id,
+                                 entry_bci,
+                                 offsets,
+                                 orig_pc_offset,
+                                 debug_info, dependencies, code_buffer,
+                                 frame_words, oop_map_set,
+                                 handler_table, &implicit_tbl,
+                                 compiler, comp_level, installed_code, speculation_log);
 
-    // Free codeBlobs
-    //code_buffer->free_blob();
+      // Free codeBlobs
+      //code_buffer->free_blob();
 
-    if (nm == NULL) {
-      // The CodeCache is full.  Print out warning and disable compilation.
-      {
-        MutexUnlocker ml(Compile_lock);
-        MutexUnlocker locker(MethodCompileQueue_lock);
-        CompileBroker::handle_full_code_cache();
-      }
-    } else {
-      nm->set_has_unsafe_access(has_unsafe_access);
+      if (nm == NULL) {
+        // The CodeCache is full.  Print out warning and disable compilation.
+        {
+          MutexUnlocker ml(Compile_lock);
+          MutexUnlocker locker(MethodCompileQueue_lock);
+          CompileBroker::handle_full_code_cache();
+        }
+      } else {
+        nm->set_has_unsafe_access(has_unsafe_access);
+
+        // 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);
 
-      // Record successful registration.
-      // (Put nm into the task handle *before* publishing to the Java heap.)
-      if (task != NULL)  task->set_code(nm);
-
-      if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) {
-        if (entry_bci == InvocationEntryBci) {
-          if (TieredCompilation) {
-            // If there is an old version we're done with it
-            nmethod* old = method->code();
-            if (TraceMethodReplacement && old != NULL) {
+        if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) {
+          if (entry_bci == InvocationEntryBci) {
+            if (TieredCompilation) {
+              // If there is an old version we're done with it
+              nmethod* old = method->code();
+              if (TraceMethodReplacement && old != NULL) {
+                ResourceMark rm;
+                char *method_name = method->name_and_sig_as_C_string();
+                tty->print_cr("Replacing method %s", method_name);
+              }
+              if (old != NULL ) {
+                old->make_not_entrant();
+              }
+            }
+            if (TraceNMethodInstalls) {
               ResourceMark rm;
               char *method_name = method->name_and_sig_as_C_string();
-              tty->print_cr("Replacing method %s", method_name);
-            }
-            if (old != NULL ) {
-              old->make_not_entrant();
+              ttyLocker ttyl;
+              tty->print_cr("Installing method (%d) %s [entry point: %p]",
+                            comp_level,
+                            method_name, nm->entry_point());
             }
-          }
-          if (TraceNMethodInstalls) {
-            ResourceMark rm;
-            char *method_name = method->name_and_sig_as_C_string();
-            ttyLocker ttyl;
-            tty->print_cr("Installing method (%d) %s [entry point: %p]",
-                          comp_level,
-                          method_name, nm->entry_point());
+            // Allow the code to be executed
+            method->set_code(method, nm);
+          } else {
+            if (TraceNMethodInstalls ) {
+              ResourceMark rm;
+              char *method_name = method->name_and_sig_as_C_string();
+              ttyLocker ttyl;
+              tty->print_cr("Installing osr method (%d) %s @ %d",
+                            comp_level,
+                            method_name,
+                            entry_bci);
+            }
+            InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm);
           }
-          // Allow the code to be executed
-          method->set_code(method, nm);
-        } else {
-          if (TraceNMethodInstalls ) {
-            ResourceMark rm;
-            char *method_name = method->name_and_sig_as_C_string();
-            ttyLocker ttyl;
-            tty->print_cr("Installing osr method (%d) %s @ %d",
-                          comp_level,
-                          method_name,
-                          entry_bci);
-          }
-          InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm);
-
         }
       }
+      result = nm != NULL ? GraalEnv::ok :GraalEnv::cache_full;
     }
   }
+
+  // String creation must be done outside lock
+  if (failure_detail != NULL) {
+    // A failure to allocate the string is silently ignored.
+    Handle message = java_lang_String::create_from_str(failure_detail, THREAD);
+    HotSpotCompiledNmethod::set_installationFailureMessage(compiled_code, message());
+  }
+
   // JVMTI -- compiled method notification (must be done outside lock)
   if (nm != NULL) {
     nm->post_compiled_method_load_event();
-    return GraalEnv::ok;
   }
 
-  return GraalEnv::cache_full;
+  return result;
 }
 
--- a/src/share/vm/graal/graalEnv.hpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalEnv.hpp	Sat Feb 21 19:55:33 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, Handle compiled_code, GraalEnv* env, char** failure_detail);
 
 public:
+  CompileTask* task() { return _task; }
+
   // Register the result of a compilation.
   static GraalEnv::CodeInstallResult register_method(
                        methodHandle&             target,
@@ -141,10 +152,11 @@
                        AbstractCompiler*         compiler,
                        DebugInformationRecorder* debug_info,
                        Dependencies*             dependencies,
-                       CompileTask*              task,
+                       GraalEnv*                 env,
                        int                       compile_id,
                        bool                      has_unsafe_access,
                        Handle                    installed_code,
+                       Handle                    compiled_code,
                        Handle                    speculation_log);
 
   // converts the Klass* representing the holder of a method into a
--- a/src/share/vm/graal/graalJavaAccess.hpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Sat Feb 21 19:55:33 2015 +0100
@@ -82,9 +82,10 @@
   end_class                                                                                                                                                    \
   start_class(HotSpotCompiledNmethod)                                                                                                                          \
     oop_field(HotSpotCompiledNmethod, method, "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;")                                                     \
+    oop_field(HotSpotCompiledNmethod, installationFailureMessage, "Ljava/lang/String;")                                                                        \
     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 +97,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	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Sat Feb 21 19:55:33 2015 +0100
@@ -31,11 +31,12 @@
 #include "graal/graalEnv.hpp"
 
 #define VM_STRUCTS_GRAAL(nonstatic_field, static_field)                       \
-  nonstatic_field(InstanceKlass, _graal_node_class, oop)                      \
   nonstatic_field(ThreadShadow,  _pending_deoptimization, int)                \
   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)                   \
 
--- a/src/share/vm/oops/instanceKlass.cpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/oops/instanceKlass.cpp	Sat Feb 21 19:55:33 2015 +0100
@@ -294,9 +294,6 @@
   set_init_state(InstanceKlass::allocated);
   set_init_thread(NULL);
   set_reference_type(rt);
-#ifdef GRAAL
-  set_graal_node_class(NULL);
-#endif
   set_oop_map_cache(NULL);
   set_jni_ids(NULL);
   set_osr_nmethods_head(NULL);
@@ -326,13 +323,6 @@
   set_layout_helper(Klass::instance_layout_helper(0, true));
 }
 
-#ifdef GRAAL
-void InstanceKlass::oops_do(OopClosure* cl) {
-  Klass::oops_do(cl);
-  cl->do_oop(adr_graal_node_class());
-}
-#endif
-
 void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
                                        Array<Method*>* methods) {
   if (methods != NULL && methods != Universe::the_empty_method_array() &&
@@ -1208,29 +1198,6 @@
     JavaCalls::call(&result, h_method, &args, CHECK); // Static call (no args)
   }
 
-#ifdef GRAAL
-  if (SystemDictionary::Node_klass() != NULL && this_oop->is_subtype_of(SystemDictionary::Node_klass())) {
-    if (this_oop() != SystemDictionary::Node_klass()) {
-      if (!GraalRuntime::is_HotSpotGraalRuntime_initialized() && JavaAssertions::systemClassDefault() == false) {
-        // We want to ensure that the process of initializing HotSpotGraalRuntime
-        // is fast since it executes at VM startup. We must avoid triggering
-        // class initialization of any Node classes during this process.
-        ResourceMark rm;
-        char buf[200];
-        jio_snprintf(buf, sizeof(buf), "Node subclass %s must not be initialized before HotSpotGraalRuntime is initialized", this_oop->name()->as_C_string());
-        THROW_MSG(vmSymbols::java_lang_InternalError(), buf);
-      }
-      // Create the NodeClass for a Node subclass.
-      TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/Class;)Lcom/oracle/graal/graph/NodeClass;", CHECK);
-      JavaValue result(T_OBJECT);
-      JavaCalls::call_static(&result, SystemDictionary::NodeClass_klass(), vmSymbols::get_name(), sig, this_oop->java_mirror(), CHECK);
-      this_oop->set_graal_node_class((oop) result.get_jobject());
-    } else {
-      // A NodeClass cannot be created for Node due to checks in
-      // NodeClass.FieldScanner.scanField()
-    }
-  }
-#endif
 }
 
 
@@ -2310,10 +2277,6 @@
   }
   init_implementor();
 
-#ifdef GRAAL
-  set_graal_node_class(NULL);
-#endif
-
   constants()->remove_unshareable_info();
 
   for (int i = 0; i < methods()->length(); i++) {
--- a/src/share/vm/oops/instanceKlass.hpp	Sat Feb 21 19:47:33 2015 +0100
+++ b/src/share/vm/oops/instanceKlass.hpp	Sat Feb 21 19:55:33 2015 +0100
@@ -241,10 +241,6 @@
   Thread*         _init_thread;          // Pointer to current thread doing initialization (to handle recusive initialization)
   int             _vtable_len;           // length of Java vtable (in words)
   int             _itable_len;           // length of Java itable (in words)
-#ifdef GRAAL
-  // com/oracle/graal/graph/NodeClass instance mirroring this class
-  oop             _graal_node_class;
-#endif
   OopMapCache*    volatile _oop_map_cache;   // OopMapCache for all methods in the klass (allocated lazily)
   MemberNameTable* _member_names;        // Member names
   JNIid*          _jni_ids;              // First JNI identifier for static fields in this class
@@ -751,16 +747,6 @@
   void call_class_initializer(TRAPS);
   void set_initialization_state_and_notify(ClassState state, TRAPS);
 
-#ifdef GRAAL
-  // Graal com.oracle.graal.graph.NodeClass mirror
-  oop graal_node_class()           { return _graal_node_class;               }
-  void set_graal_node_class(oop m) { klass_oop_store(&_graal_node_class, m); }
-  oop* adr_graal_node_class()      { return (oop*)&this->_graal_node_class;  }
-
-  // GC support
-  virtual void oops_do(OopClosure* cl);
-#endif
-
   // OopMapCache support
   OopMapCache* oop_map_cache()               { return _oop_map_cache; }
   void set_oop_map_cache(OopMapCache *cache) { _oop_map_cache = cache; }
--- a/test/whitelist_baseline.txt	Sat Feb 21 19:47:33 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-com.oracle.graal.jtt.loop.Loop03
-com.oracle.graal.jtt.loop.Loop04
-com.oracle.graal.jtt.loop.Loop08
-com.oracle.graal.jtt.loop.Loop11
-com.oracle.graal.jtt.bytecode.BC_iadd
-com.oracle.graal.jtt.bytecode.BC_iadd2
-com.oracle.graal.jtt.bytecode.BC_iadd3
-com.oracle.graal.jtt.bytecode.BC_ifeq_2
-com.oracle.graal.jtt.bytecode.BC_ifeq_3
-com.oracle.graal.jtt.bytecode.BC_ifeq
-com.oracle.graal.jtt.bytecode.BC_aload_3
-com.oracle.graal.jtt.bytecode.BC_aload_2
-com.oracle.graal.jtt.bytecode.BC_aload_1
-com.oracle.graal.jtt.bytecode.BC_aload_0
-com.oracle.graal.jtt.bytecode.BC_areturn
-com.oracle.graal.jtt.bytecode.BC_freturn
-com.oracle.graal.jtt.bytecode.BC_iconst
-com.oracle.graal.jtt.bytecode.BC_ireturn
-com.oracle.graal.jtt.bytecode.BC_lreturn
-com.oracle.graal.jtt.bytecode.BC_getstatic_b
-com.oracle.graal.jtt.bytecode.BC_getstatic_c
-com.oracle.graal.jtt.bytecode.BC_getstatic_d
-com.oracle.graal.jtt.bytecode.BC_getstatic_f
-com.oracle.graal.jtt.bytecode.BC_getstatic_i
-com.oracle.graal.jtt.bytecode.BC_getstatic_l
-com.oracle.graal.jtt.bytecode.BC_getstatic_s
-com.oracle.graal.jtt.bytecode.BC_getstatic_z
-com.oracle.graal.jtt.bytecode.BC_arraylength