changeset 19678:96ab2078eeaf

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Mon, 02 Mar 2015 19:11:22 +0100
parents 00d7b0adaf66 (current diff) a0284c1724e6 (diff)
children 87d5316e171b
files graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.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/meta/HotSpotCodeCacheProvider.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMonitorValue.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/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/StandardGraphBuilderPlugins.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBreakpointOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCompare.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCJumpOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMathIntrinsicOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionBase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRHighTier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRHighTierPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRLowTier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRLowTierPhase.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRMidTier.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRMidTierPhase.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/CompilationConstantNode.java
diffstat 793 files changed, 11380 insertions(+), 6501 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Mar 02 18:44:14 2015 +0100
+++ b/.hgtags	Mon Mar 02 19:11:22 2015 +0100
@@ -525,3 +525,4 @@
 ae5b662550836e851c39e4fbb5c80517fc62488f graal-0.5
 3b60f720b955c466d913abb0113af9b38962950b graal-0.6
 1b0ef9634252c422b6f9839fc62eebc112545486 gpu-0.1
+9a12234da10cfa6934617274c203672389a1bbdd baseline-0.1
--- a/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapSet.java	Mon Mar 02 19:11:22 2015 +0100
@@ -65,9 +65,6 @@
       }
     }
 
-    public void visitValueLocation(Address valueAddr) {
-    }
-
     public void visitNarrowOopLocation(Address narrowOopAddr) {
       addressVisitor.visitCompOopAddress(narrowOopAddr);
     }
@@ -198,9 +195,9 @@
       }
     }
 
-    // We want narow oop, value and oop oop_types
+    // We want narow oop and  oop oop_types
     OopMapValue.OopTypes[] values = new OopMapValue.OopTypes[] {
-      OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.VALUE_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE
+      OopMapValue.OopTypes.OOP_VALUE, OopMapValue.OopTypes.NARROWOOP_VALUE
     };
 
     {
@@ -213,8 +210,6 @@
             // to detect in the debugging system
             // assert(Universe::is_heap_or_null(*loc), "found non oop pointer");
             visitor.visitOopLocation(loc);
-          } else if (omv.getType() == OopMapValue.OopTypes.VALUE_VALUE) {
-            visitor.visitValueLocation(loc);
           } else if (omv.getType() == OopMapValue.OopTypes.NARROWOOP_VALUE) {
             visitor.visitNarrowOopLocation(loc);
           }
--- a/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapValue.java	Mon Mar 02 19:11:22 2015 +0100
@@ -49,7 +49,6 @@
   // Types of OopValues
   static int UNUSED_VALUE;
   static int OOP_VALUE;
-  static int VALUE_VALUE;
   static int NARROWOOP_VALUE;
   static int CALLEE_SAVED_VALUE;
   static int DERIVED_OOP_VALUE;
@@ -73,7 +72,6 @@
     REGISTER_MASK_IN_PLACE = db.lookupIntConstant("OopMapValue::register_mask_in_place").intValue();
     UNUSED_VALUE           = db.lookupIntConstant("OopMapValue::unused_value").intValue();
     OOP_VALUE              = db.lookupIntConstant("OopMapValue::oop_value").intValue();
-    VALUE_VALUE            = db.lookupIntConstant("OopMapValue::value_value").intValue();
     NARROWOOP_VALUE        = db.lookupIntConstant("OopMapValue::narrowoop_value").intValue();
     CALLEE_SAVED_VALUE     = db.lookupIntConstant("OopMapValue::callee_saved_value").intValue();
     DERIVED_OOP_VALUE      = db.lookupIntConstant("OopMapValue::derived_oop_value").intValue();
@@ -82,7 +80,6 @@
   public static abstract class OopTypes {
     public static final OopTypes UNUSED_VALUE       = new OopTypes() { int getValue() { return OopMapValue.UNUSED_VALUE;       }};
     public static final OopTypes OOP_VALUE          = new OopTypes() { int getValue() { return OopMapValue.OOP_VALUE;          }};
-    public static final OopTypes VALUE_VALUE        = new OopTypes() { int getValue() { return OopMapValue.VALUE_VALUE;        }};
     public static final OopTypes NARROWOOP_VALUE    = new OopTypes() { int getValue() { return OopMapValue.NARROWOOP_VALUE;         }};
     public static final OopTypes CALLEE_SAVED_VALUE = new OopTypes() { int getValue() { return OopMapValue.CALLEE_SAVED_VALUE; }};
     public static final OopTypes DERIVED_OOP_VALUE  = new OopTypes() { int getValue() { return OopMapValue.DERIVED_OOP_VALUE;  }};
@@ -105,7 +102,6 @@
 
   // Querying
   public boolean isOop()         { return (getValue() & TYPE_MASK_IN_PLACE) == OOP_VALUE;          }
-  public boolean isValue()       { return (getValue() & TYPE_MASK_IN_PLACE) == VALUE_VALUE;        }
   public boolean isNarrowOop()   { return (getValue() & TYPE_MASK_IN_PLACE) == NARROWOOP_VALUE;    }
   public boolean isCalleeSaved() { return (getValue() & TYPE_MASK_IN_PLACE) == CALLEE_SAVED_VALUE; }
   public boolean isDerivedOop()  { return (getValue() & TYPE_MASK_IN_PLACE) == DERIVED_OOP_VALUE;  }
@@ -117,7 +113,6 @@
     int which = (getValue() & TYPE_MASK_IN_PLACE);
          if (which == UNUSED_VALUE) return OopTypes.UNUSED_VALUE;
     else if (which == OOP_VALUE)    return OopTypes.OOP_VALUE;
-    else if (which == VALUE_VALUE)  return OopTypes.VALUE_VALUE;
     else if (which == NARROWOOP_VALUE)   return OopTypes.NARROWOOP_VALUE;
     else if (which == CALLEE_SAVED_VALUE) return OopTypes.CALLEE_SAVED_VALUE;
     else if (which == DERIVED_OOP_VALUE)  return OopTypes.DERIVED_OOP_VALUE;
--- a/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/OopMapVisitor.java	Mon Mar 02 19:11:22 2015 +0100
@@ -31,6 +31,5 @@
 public interface OopMapVisitor {
   public void visitOopLocation(Address oopAddr);
   public void visitDerivedOopLocation(Address baseOopAddr, Address derivedOopAddr);
-  public void visitValueLocation(Address valueAddr);
   public void visitNarrowOopLocation(Address narrowOopAddr);
 }
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Frame.java	Mon Mar 02 19:11:22 2015 +0100
@@ -544,9 +544,6 @@
       }
     }
 
-    public void visitValueLocation(Address valueAddr) {
-    }
-
     public void visitNarrowOopLocation(Address compOopAddr) {
       addressVisitor.visitCompOopAddress(compOopAddr);
     }
--- a/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -1222,9 +1222,6 @@
       oms = new OopMapStream(map, OopMapValue.OopTypes.NARROWOOP_VALUE);
       buf.append(omvIterator.iterate(oms, "NarrowOops:", false));
 
-      oms = new OopMapStream(map, OopMapValue.OopTypes.VALUE_VALUE);
-      buf.append(omvIterator.iterate(oms, "Values:", false));
-
       oms = new OopMapStream(map, OopMapValue.OopTypes.CALLEE_SAVED_VALUE);
       buf.append(omvIterator.iterate(oms, "Callee saved:",  true));
 
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BailoutException.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BailoutException.java	Mon Mar 02 19:11:22 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/BytecodeFrame.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/BytecodeFrame.java	Mon Mar 02 19:11:22 2015 +0100
@@ -170,7 +170,7 @@
                 Kind kind = values[i].getKind();
                 if (kind.needsTwoSlots()) {
                     assert values.length > i + 1 : String.format("missing second word %s", this);
-                    assert values[i + 1] == null || values[i + 1].getKind() == Kind.Illegal;
+                    assert values[i + 1] == null || values[i + 1].getKind() == Kind.Illegal : this;
                 }
             }
         }
--- a/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CalleeSaveLayout.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/CallingConvention.java	Mon Mar 02 19:11:22 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/DisassemblerProvider.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/DisassemblerProvider.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/ForeignCallLinkage.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/MemoryBarriers.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/RegisterAttributes.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/SpeculationLog.java	Mon Mar 02 19:11:22 2015 +0100
@@ -29,7 +29,7 @@
 
 /**
  * Manages a list of unique deoptimization reasons.
- * 
+ *
  */
 public abstract class SpeculationLog {
     private volatile Object lastFailed;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.code/src/com/oracle/graal/api/code/StackLockValue.java	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,91 @@
+/*
+ * 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
+ * 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.api.code;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Represents lock information in the debug information.
+ */
+public final class StackLockValue extends AbstractValue implements JavaValue {
+
+    private static final long serialVersionUID = 8241681800464483691L;
+
+    private JavaValue owner;
+    private StackSlotValue slot;
+    private final boolean eliminated;
+
+    public StackLockValue(JavaValue owner, StackSlotValue slot, boolean eliminated) {
+        super(LIRKind.Illegal);
+        this.owner = owner;
+        this.slot = slot;
+        this.eliminated = eliminated;
+    }
+
+    public JavaValue getOwner() {
+        return owner;
+    }
+
+    public void setOwner(JavaValue newOwner) {
+        this.owner = newOwner;
+    }
+
+    public Value getSlot() {
+        return slot;
+    }
+
+    public boolean isEliminated() {
+        return eliminated;
+    }
+
+    @Override
+    public String toString() {
+        return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]";
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 43;
+        int result = super.hashCode();
+        result = prime * result + (eliminated ? 1231 : 1237);
+        result = prime * result + owner.hashCode();
+        result = prime * result + slot.hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj instanceof StackLockValue) {
+            StackLockValue other = (StackLockValue) obj;
+            return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot);
+        }
+        return false;
+    }
+
+    public void setSlot(StackSlotValue stackSlot) {
+        assert slot == null || (isVirtualStackSlot(slot) && (slot.equals(stackSlot) || isStackSlot(stackSlot))) : String.format("Can not set slot for %s to %s", this, stackSlot);
+        slot = stackSlot;
+    }
+}
--- a/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ControlFlowAnchorDirectiveTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/IterationDirectiveTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/OpaqueDirectiveTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.directives.test/src/com/oracle/graal/api/directives/test/ProbabilityDirectiveTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/AbstractJavaProfile.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/BytecodeDisassemblerProvider.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ExceptionHandler.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ProfilingInfo.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Address.java	Mon Mar 02 19:11:22 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.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Mon Mar 02 19:11:22 2015 +0100
@@ -999,7 +999,7 @@
 
     // @formatter:off
     /**
-     * Branch on (Integer|Floatingpoint) Condition Codes
+     * Branch on (Integer|Floatingpoint) Condition Codes.
      * <pre>
      * | 00  |annul| cond| op2 |               disp22                 |
      * |31 30|29   |28 25|24 22|21                                   0|
@@ -1043,7 +1043,7 @@
 
     // @formatter:off
     /**
-     * Used for fbpcc (Float) and bpcc (Integer)
+     * Used for fbpcc (Float) and bpcc (Integer).
      * <pre>
      * | 00  |an|cond | op2 |cc1 2|p |           disp19               |
      * |31 30|29|28 25|24 22|21 20|19|                               0|
@@ -1237,12 +1237,12 @@
         int d10 = !l.isBound() ? patchUnbound(l) : (l.position() - position()) / 4;
         assert isSimm(d10, 10) && isImm(rs2, 5);
         d10 &= (1 << 10) - 1;
-        final int c_lo = cf.value & 0b111;
-        final int c_hi = cf.value >> 3;
-        final int d10_lo = d10 & ((1 << 8) - 1);
-        final int d10_hi = d10 >> 8;
-        int a = c_hi << 4 | 0b1000 | c_lo;
-        int b = cc2 << 21 | d10_hi << D10HI_SHIFT | rs1.encoding << 14 | i << 13 | d10_lo << D10LO_SHIFT | rs2;
+        final int cLo = cf.value & 0b111;
+        final int cHi = cf.value >> 3;
+        final int d10Lo = d10 & ((1 << 8) - 1);
+        final int d10Hi = d10 >> 8;
+        int a = cHi << 4 | 0b1000 | cLo;
+        int b = cc2 << 21 | d10Hi << D10HI_SHIFT | rs1.encoding << 14 | i << 13 | d10Lo << D10LO_SHIFT | rs2;
         fmt00(a, Op2s.Bpr.value, b);
     }
 
--- a/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeLookupSwitch.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeLookupSwitch.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeStream.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeSwitch.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/BytecodeTableSwitch.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.bytecode/src/com/oracle/graal/bytecode/Bytes.java	Mon Mar 02 19:11:22 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.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -81,7 +81,7 @@
 
     private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(Kind.Int));
 
-    private class AMD64SpillMoveFactory implements LIR.SpillMoveFactory {
+    private class AMD64SpillMoveFactory implements LIRGeneratorTool.SpillMoveFactory {
 
         @Override
         public LIRInstruction createMove(AllocatableValue result, Value input) {
@@ -91,7 +91,10 @@
 
     public AMD64LIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
         super(lirKindTool, providers, cc, lirGenRes);
-        lirGenRes.getLIR().setSpillMoveFactory(new AMD64SpillMoveFactory());
+    }
+
+    public SpillMoveFactory getSpillMoveFactory() {
+        return new AMD64SpillMoveFactory();
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon Mar 02 19:11:22 2015 +0100
@@ -61,7 +61,21 @@
         if ((valueNode instanceof IntegerDivNode) || (valueNode instanceof IntegerRemNode)) {
             FixedBinaryNode divRem = (FixedBinaryNode) valueNode;
             FixedNode node = divRem.next();
-            while (node instanceof FixedWithNextNode) {
+            while (true) {
+                if (node instanceof IfNode) {
+                    IfNode ifNode = (IfNode) node;
+                    double probability = ifNode.getTrueSuccessorProbability();
+                    if (probability == 1.0) {
+                        node = ifNode.trueSuccessor();
+                    } else if (probability == 0.0) {
+                        node = ifNode.falseSuccessor();
+                    } else {
+                        break;
+                    }
+                } else if (!(node instanceof FixedWithNextNode)) {
+                    break;
+                }
+
                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
                 if (((fixedWithNextNode instanceof IntegerDivNode) || (fixedWithNextNode instanceof IntegerRemNode)) && fixedWithNextNode.getClass() != divRem.getClass()) {
                     FixedBinaryNode otherDivRem = (FixedBinaryNode) fixedWithNextNode;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/FieldIntrospection.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Mon Mar 02 19:11:22 2015 +0100
@@ -143,6 +143,9 @@
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<String> PrintFilter = new OptionValue<>(null);
 
+    @Option(help = "", type = OptionType.Debug)
+    public static final StableOptionValue<Boolean> DumpDuringGraphBuilding = new StableOptionValue<>(false);
+
     // Debug settings:
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> BootstrapReplacements = new OptionValue<>(false);
@@ -201,7 +204,7 @@
     public static final OptionValue<Boolean> PrintBailout = new OptionValue<>(false);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionValue<Boolean> TraceEscapeAnalysis = new OptionValue<>(false);
+    public static final StableOptionValue<Boolean> TraceEscapeAnalysis = new StableOptionValue<>(false);
 
     @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> ExitVMOnBailout = new OptionValue<>(false);
@@ -307,7 +310,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);
@@ -334,6 +337,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/alloc/ComputeBlockOrder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/alloc/ComputeBlockOrder.java	Mon Mar 02 19:11:22 2015 +0100
@@ -66,7 +66,7 @@
      *
      * @return sorted list of blocks
      */
-    public static <T extends AbstractBlock<T>> List<T> computeLinearScanOrder(int blockCount, T startBlock) {
+    public static <T extends AbstractBlockBase<T>> List<T> computeLinearScanOrder(int blockCount, T startBlock) {
         List<T> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
         PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
@@ -80,7 +80,7 @@
      *
      * @return sorted list of blocks
      */
-    public static <T extends AbstractBlock<T>> List<T> computeCodeEmittingOrder(int blockCount, T startBlock) {
+    public static <T extends AbstractBlockBase<T>> List<T> computeCodeEmittingOrder(int blockCount, T startBlock) {
         List<T> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
         PriorityQueue<T> worklist = initializeWorklist(startBlock, visitedBlocks);
@@ -92,7 +92,7 @@
     /**
      * Iteratively adds paths to the code emission block order.
      */
-    private static <T extends AbstractBlock<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> void computeCodeEmittingOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         while (!worklist.isEmpty()) {
             T nextImportantPath = worklist.poll();
             addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks);
@@ -102,7 +102,7 @@
     /**
      * Iteratively adds paths to the linear scan block order.
      */
-    private static <T extends AbstractBlock<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> void computeLinearScanOrder(List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         while (!worklist.isEmpty()) {
             T nextImportantPath = worklist.poll();
             addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks);
@@ -112,7 +112,7 @@
     /**
      * Initializes the priority queue used for the work list of blocks and adds the start block.
      */
-    private static <T extends AbstractBlock<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> PriorityQueue<T> initializeWorklist(T startBlock, BitSet visitedBlocks) {
         PriorityQueue<T> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<>());
         result.add(startBlock);
         visitedBlocks.set(startBlock.getId());
@@ -122,7 +122,7 @@
     /**
      * Add a linear path to the linear scan order greedily following the most likely successor.
      */
-    private static <T extends AbstractBlock<T>> void addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> void addPathToLinearScanOrder(T block, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         block.setLinearScanNumber(order.size());
         order.add(block);
         T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
@@ -151,7 +151,7 @@
     /**
      * Add a linear path to the code emission order greedily following the most likely successor.
      */
-    private static <T extends AbstractBlock<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> void addPathToCodeEmittingOrder(T initialBlock, List<T> order, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         T block = initialBlock;
         while (block != null) {
             // Skip loop headers if there is only a single loop end block to
@@ -191,7 +191,7 @@
     /**
      * Adds a block to the ordering.
      */
-    private static <T extends AbstractBlock<T>> void addBlock(T header, List<T> order) {
+    private static <T extends AbstractBlockBase<T>> void addBlock(T header, List<T> order) {
         assert !order.contains(header) : "Cannot insert block twice";
         order.add(header);
     }
@@ -199,7 +199,7 @@
     /**
      * Find the highest likely unvisited successor block of a given block.
      */
-    private static <T extends AbstractBlock<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) {
         T result = null;
         for (T successor : block.getSuccessors()) {
             assert successor.probability() >= 0.0 : "Probabilities must be positive";
@@ -216,7 +216,7 @@
     /**
      * Add successor blocks into the given work list if they are not already marked as visited.
      */
-    private static <T extends AbstractBlock<T>> void enqueueSuccessors(T block, PriorityQueue<T> worklist, BitSet visitedBlocks) {
+    private static <T extends AbstractBlockBase<T>> void enqueueSuccessors(T block, PriorityQueue<T> worklist, BitSet visitedBlocks) {
         for (T successor : block.getSuccessors()) {
             if (!visitedBlocks.get(successor.getId())) {
                 visitedBlocks.set(successor.getId());
@@ -229,14 +229,14 @@
      * Skip the loop header block if the loop consists of more than one block and it has only a
      * single loop end block.
      */
-    private static <T extends AbstractBlock<T>> boolean skipLoopHeader(AbstractBlock<T> block) {
+    private static <T extends AbstractBlockBase<T>> boolean skipLoopHeader(AbstractBlockBase<T> block) {
         return (block.isLoopHeader() && !block.isLoopEnd() && block.getLoop().numBackedges() == 1);
     }
 
     /**
      * Checks that the ordering contains the expected number of blocks.
      */
-    private static boolean checkOrder(List<? extends AbstractBlock<?>> order, int expectedBlockCount) {
+    private static boolean checkOrder(List<? extends AbstractBlockBase<?>> order, int expectedBlockCount) {
         assert order.size() == expectedBlockCount : String.format("Number of blocks in ordering (%d) does not match expected block count (%d)", order.size(), expectedBlockCount);
         return true;
     }
@@ -244,7 +244,7 @@
     /**
      * Comparator for sorting blocks based on loop depth and probability.
      */
-    private static class BlockOrderComparator<T extends AbstractBlock<T>> implements Comparator<T> {
+    private static class BlockOrderComparator<T extends AbstractBlockBase<T>> implements Comparator<T> {
 
         @Override
         public int compare(T a, T b) {
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,71 +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.compiler.common.cfg;
-
-import java.util.*;
-
-public interface AbstractBlock<T extends AbstractBlock<T>> {
-
-    int getId();
-
-    Loop<T> getLoop();
-
-    void setLoop(Loop<T> loop);
-
-    int getLoopDepth();
-
-    boolean isLoopHeader();
-
-    boolean isLoopEnd();
-
-    boolean isExceptionEntry();
-
-    List<T> getPredecessors();
-
-    int getPredecessorCount();
-
-    List<T> getSuccessors();
-
-    int getSuccessorCount();
-
-    int getLinearScanNumber();
-
-    void setLinearScanNumber(int linearScanNumber);
-
-    boolean isAligned();
-
-    void setAlign(boolean align);
-
-    T getDominator();
-
-    void setDominator(T block);
-
-    List<T> getDominated();
-
-    void setDominated(List<T> blocks);
-
-    T getPostdominator();
-
-    double probability();
-
-}
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlockBase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlockBase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,9 +24,10 @@
 
 import java.util.*;
 
-public abstract class AbstractBlockBase<T extends AbstractBlock<T>> implements AbstractBlock<T> {
+public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
 
     protected int id;
+    protected int domDepth;
 
     protected List<T> predecessors;
     protected List<T> successors;
@@ -72,6 +73,11 @@
 
     public void setDominator(T dominator) {
         this.dominator = dominator;
+        this.domDepth = dominator.domDepth + 1;
+    }
+
+    public int getDominatorDepth() {
+        return domDepth;
     }
 
     public List<T> getDominated() {
@@ -113,4 +119,20 @@
     public void setAlign(boolean align) {
         this.align = align;
     }
+
+    public abstract boolean isExceptionEntry();
+
+    public abstract Loop<T> getLoop();
+
+    public abstract int getLoopDepth();
+
+    public abstract boolean isLoopEnd();
+
+    public abstract boolean isLoopHeader();
+
+    public abstract T getPostdominator();
+
+    public abstract double probability();
+
+    public abstract T getDominator(int distance);
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractControlFlowGraph.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,9 +24,7 @@
 
 import java.util.*;
 
-import com.oracle.graal.compiler.common.*;
-
-public interface AbstractControlFlowGraph<T extends AbstractBlock<T>> {
+public interface AbstractControlFlowGraph<T extends AbstractBlockBase<T>> {
 
     int BLOCK_ID_INITIAL = -1;
     int BLOCK_ID_VISITED = -2;
@@ -48,7 +46,7 @@
     /**
      * Computes the dominators of control flow graph.
      */
-    static <T extends AbstractBlock<T>> void computeDominators(AbstractControlFlowGraph<T> cfg) {
+    static <T extends AbstractBlockBase<T>> void computeDominators(AbstractControlFlowGraph<T> cfg) {
         List<T> reversePostOrder = cfg.getBlocks();
         assert reversePostOrder.get(0).getPredecessorCount() == 0 : "start block has no predecessor and therefore no dominator";
         for (int i = 1; i < reversePostOrder.size(); i++) {
@@ -72,27 +70,23 @@
     /**
      * True if block {@code a} is dominated by block {@code b}.
      */
-    static boolean isDominatedBy(AbstractBlock<?> a, AbstractBlock<?> b) {
-        assert a != null;
-        AbstractBlock<?> dominator = a;
-        int i = 0;
-        while (dominator != null) {
-            if (i++ == Integer.MAX_VALUE) { // For safety
-                throw GraalInternalError.shouldNotReachHere();
-            }
-            if (dominator == b) {
-                return true;
-            }
-            dominator = dominator.getDominator();
+    static boolean isDominatedBy(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        assert a != null && b != null;
+        if (a == b) {
+            return true;
         }
-        return false;
+        if (a.getDominatorDepth() < b.getDominatorDepth()) {
+            return false;
+        }
+
+        return b == (AbstractBlockBase<?>) a.getDominator(a.getDominatorDepth() - b.getDominatorDepth());
     }
 
     /**
      * True if block {@code a} dominates block {@code b}.
      */
-    static boolean dominates(AbstractBlock<?> a, AbstractBlock<?> b) {
-        assert a != null;
+    static boolean dominates(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
+        assert a != null && b != null;
         return isDominatedBy(b, a);
     }
 
@@ -104,31 +98,36 @@
      * @see #getBlocks()
      * @see CFGVerifier
      */
-    static AbstractBlock<?> commonDominator(AbstractBlock<?> a, AbstractBlock<?> b) {
+    static AbstractBlockBase<?> commonDominator(AbstractBlockBase<?> a, AbstractBlockBase<?> b) {
         if (a == null) {
             return b;
         }
         if (b == null) {
             return a;
         }
-        AbstractBlock<?> iterA = a;
-        AbstractBlock<?> iterB = b;
+
+        AbstractBlockBase<?> iterA = a;
+        AbstractBlockBase<?> iterB = b;
+        int aDomDepth = a.getDominatorDepth();
+        int bDomDepth = b.getDominatorDepth();
+        if (aDomDepth > bDomDepth) {
+            iterA = a.getDominator(aDomDepth - bDomDepth);
+        } else {
+            iterB = b.getDominator(bDomDepth - aDomDepth);
+        }
+
         while (iterA != iterB) {
-            if (iterA.getId() > iterB.getId()) {
-                iterA = iterA.getDominator();
-            } else {
-                assert iterB.getId() > iterA.getId();
-                iterB = iterB.getDominator();
-            }
+            iterA = iterA.getDominator();
+            iterB = iterB.getDominator();
         }
         return iterA;
     }
 
     /**
-     * @see AbstractControlFlowGraph#commonDominator(AbstractBlock, AbstractBlock)
+     * @see AbstractControlFlowGraph#commonDominator(AbstractBlockBase, AbstractBlockBase)
      */
     @SuppressWarnings("unchecked")
-    static <T extends AbstractBlock<T>> T commonDominatorTyped(T a, T b) {
+    static <T extends AbstractBlockBase<T>> T commonDominatorTyped(T a, T b) {
         return (T) commonDominator(a, b);
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/BlockMap.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/BlockMap.java	Mon Mar 02 19:11:22 2015 +0100
@@ -31,11 +31,11 @@
         data = (T[]) new Object[cfg.getBlocks().size()];
     }
 
-    public T get(AbstractBlock<?> block) {
+    public T get(AbstractBlockBase<?> block) {
         return data[block.getId()];
     }
 
-    public void put(AbstractBlock<?> block, T value) {
+    public void put(AbstractBlockBase<?> block, T value) {
         data[block.getId()] = value;
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/CFGVerifier.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/CFGVerifier.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,7 +26,7 @@
 
 public class CFGVerifier {
 
-    public static <T extends AbstractBlock<T>, C extends AbstractControlFlowGraph<T>> boolean verify(C cfg) {
+    public static <T extends AbstractBlockBase<T>, C extends AbstractControlFlowGraph<T>> boolean verify(C cfg) {
         for (T block : cfg.getBlocks()) {
             assert block.getId() >= 0;
             assert cfg.getBlocks().get(block.getId()) == block;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/DominatorOptimizationProblem.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/DominatorOptimizationProblem.java	Mon Mar 02 19:11:22 2015 +0100
@@ -36,7 +36,7 @@
  */
 public abstract class DominatorOptimizationProblem<E extends Enum<E>, C> {
 
-    private List<? extends AbstractBlock<?>> blocks;
+    private List<? extends AbstractBlockBase<?>> blocks;
     private EnumMap<E, BitSet> flags;
     private BlockMap<C> costs;
 
@@ -47,9 +47,9 @@
         assert verify(blocks);
     }
 
-    private static boolean verify(List<? extends AbstractBlock<?>> blocks) {
+    private static boolean verify(List<? extends AbstractBlockBase<?>> blocks) {
         for (int i = 0; i < blocks.size(); i++) {
-            AbstractBlock<?> block = blocks.get(i);
+            AbstractBlockBase<?> block = blocks.get(i);
             if (i != block.getId()) {
                 assert false : String.format("Id index mismatch @ %d vs. %s.getId()==%d", i, block, block.getId());
                 return false;
@@ -58,12 +58,12 @@
         return true;
     }
 
-    public final List<? extends AbstractBlock<?>> getBlocks() {
+    public final List<? extends AbstractBlockBase<?>> getBlocks() {
         return blocks;
     }
 
-    public final AbstractBlock<?> getBlockForId(int id) {
-        AbstractBlock<?> block = blocks.get(id);
+    public final AbstractBlockBase<?> getBlockForId(int id) {
+        AbstractBlockBase<?> block = blocks.get(id);
         assert block.getId() == id : "wrong block-to-id mapping";
         return block;
     }
@@ -71,7 +71,7 @@
     /**
      * Sets a flag for a block.
      */
-    public final void set(E flag, AbstractBlock<?> block) {
+    public final void set(E flag, AbstractBlockBase<?> block) {
         BitSet bitSet = flags.get(flag);
         if (bitSet == null) {
             bitSet = new BitSet(blocks.size());
@@ -83,7 +83,7 @@
     /**
      * Checks whether a flag is set for a block.
      */
-    public final boolean get(E flag, AbstractBlock<?> block) {
+    public final boolean get(E flag, AbstractBlockBase<?> block) {
         BitSet bitSet = flags.get(flag);
         return bitSet == null ? false : bitSet.get(block.getId());
     }
@@ -91,14 +91,14 @@
     /**
      * Returns a {@linkplain Stream} of blocks for which {@code flag} is set.
      */
-    public final Stream<? extends AbstractBlock<?>> stream(E flag) {
+    public final Stream<? extends AbstractBlockBase<?>> stream(E flag) {
         return getBlocks().stream().filter(block -> get(flag, block));
     }
 
     /**
      * Returns the cost object associated with {@code block}. Might return {@code null} if not set.
      */
-    public final C getCost(AbstractBlock<?> block) {
+    public final C getCost(AbstractBlockBase<?> block) {
         C cost = costs.get(block);
         return cost;
     }
@@ -106,7 +106,7 @@
     /**
      * Sets the cost for a {@code block}.
      */
-    public final void setCost(AbstractBlock<?> block, C cost) {
+    public final void setCost(AbstractBlockBase<?> block, C cost) {
         costs.put(block, cost);
     }
 
@@ -114,13 +114,13 @@
      * Sets {@code flag} for all blocks along the dominator path from {@code block} to the root
      * until a block it finds a block where {@code flag} is already set.
      */
-    public final void setDominatorPath(E flag, AbstractBlock<?> block) {
+    public final void setDominatorPath(E flag, AbstractBlockBase<?> block) {
         BitSet bitSet = flags.get(flag);
         if (bitSet == null) {
             bitSet = new BitSet(blocks.size());
             flags.put(flag, bitSet);
         }
-        for (AbstractBlock<?> b = block; b != null && !bitSet.get(b.getId()); b = b.getDominator()) {
+        for (AbstractBlockBase<?> b = block; b != null && !bitSet.get(b.getId()); b = b.getDominator()) {
             // mark block
             bitSet.set(b.getId());
         }
@@ -129,7 +129,7 @@
     /**
      * Returns a {@link Stream} of flags associated with {@code block}.
      */
-    public final Stream<E> getFlagsForBlock(AbstractBlock<?> block) {
+    public final Stream<E> getFlagsForBlock(AbstractBlockBase<?> block) {
         return getFlags().stream().filter(flag -> get(flag, block));
     }
 
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/Loop.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/Loop.java	Mon Mar 02 19:11:22 2015 +0100
@@ -25,7 +25,7 @@
 
 import java.util.*;
 
-public abstract class Loop<T extends AbstractBlock<T>> {
+public abstract class Loop<T extends AbstractBlockBase<T>> {
 
     private final Loop<T> parent;
     private final List<Loop<T>> children;
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableCFG.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableCFG.java	Mon Mar 02 19:11:22 2015 +0100
@@ -31,7 +31,7 @@
  */
 public interface PrintableCFG {
 
-    List<? extends AbstractBlock<?>> getBlocks();
+    List<? extends AbstractBlockBase<?>> getBlocks();
 
     /**
      * Applies {@code action} to all extra property pairs (name, value) of {@code block}.
@@ -39,7 +39,7 @@
      * @param block a block from {@link #getBlocks()}.
      * @param action a {@link BiConsumer consumer}.
      */
-    default void forEachPropertyPair(AbstractBlock<?> block, BiConsumer<String, String> action) {
+    default void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
         // no extra properties per default
     }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableDominatorOptimizationProblem.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/PrintableDominatorOptimizationProblem.java	Mon Mar 02 19:11:22 2015 +0100
@@ -33,7 +33,7 @@
         super(keyType, cfg);
     }
 
-    public void forEachPropertyPair(AbstractBlock<?> block, BiConsumer<String, String> action) {
+    public void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
         // for each flag
         getFlags().forEach(flag -> ((BiConsumer<String, Boolean>) (name, value) -> action.accept(name, value ? "true" : "false")).accept(getName(flag), get(flag, block)));
         // for each property
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/ArrayMap.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/ArrayMap.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/util/IntList.java	Mon Mar 02 19:11:22 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.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.sparc.test/src/com/oracle/graal/compiler/sparc/test/SPARCAllocatorTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -47,7 +47,7 @@
 
     @Test
     public void test2() {
-        testAllocation("test2snippet", 2, 1, 0);
+        testAllocation("test2snippet", 1, 0, 0);
     }
 
     public static long test2snippet(long x) {
--- a/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.sparc/src/com/oracle/graal/compiler/sparc/SPARCLIRGenerator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -70,7 +70,7 @@
 
     private StackSlotValue tmpStackSlot;
 
-    private class SPARCSpillMoveFactory implements LIR.SpillMoveFactory {
+    private class SPARCSpillMoveFactory implements LIRGeneratorTool.SpillMoveFactory {
 
         @Override
         public LIRInstruction createMove(AllocatableValue result, Value input) {
@@ -80,7 +80,10 @@
 
     public SPARCLIRGenerator(LIRKindTool lirKindTool, Providers providers, CallingConvention cc, LIRGenerationResult lirGenRes) {
         super(lirKindTool, providers, cc, lirGenRes);
-        lirGenRes.getLIR().setSpillMoveFactory(new SPARCSpillMoveFactory());
+    }
+
+    public SpillMoveFactory getSpillMoveFactory() {
+        return new SPARCSpillMoveFactory();
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -300,8 +300,8 @@
 
     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) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CheckGraalInvariants.java	Mon Mar 02 19:11:22 2015 +0100
@@ -47,7 +47,6 @@
 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.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.phases.verify.*;
@@ -199,7 +198,6 @@
      * Checks the invariants for a single graph.
      */
     private static void checkGraph(HighTierContext context, StructuredGraph graph, boolean verifyEquals) {
-        InferStamps.inferStamps(graph);
         if (verifyEquals) {
             new VerifyUsageWithEquals(Value.class).apply(graph, context);
             new VerifyUsageWithEquals(Register.class).apply(graph, context);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/CompareCanonicalizerTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -131,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/GraalCompilerTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -294,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);
@@ -801,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IfCanonicalizerTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -194,7 +194,7 @@
 
     private void test(String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
-        ParameterNode param = graph.getNodes(ParameterNode.class).iterator().next();
+        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);
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/IntegerEqualsCanonicalizerTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -115,7 +115,7 @@
     private StructuredGraph getCanonicalizedGraph(String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
         new CanonicalizerPhase(false).apply(graph, new PhaseContext(getProviders()));
-        for (FrameState state : graph.getNodes(FrameState.class).snapshot()) {
+        for (FrameState state : graph.getNodes(FrameState.TYPE).snapshot()) {
             state.replaceAtUsages(null);
             state.safeDelete();
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LongNodeChainTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,78 @@
+/*
+ * 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.compiler.test;
+
+import org.junit.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.schedule.*;
+import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
+import com.oracle.graal.phases.tiers.*;
+
+public class LongNodeChainTest extends GraalCompilerTest {
+
+    public static final int N = 100000;
+
+    @Ignore
+    @Test
+    public void testLongAddChain() {
+        longAddChain(true);
+        longAddChain(false);
+    }
+
+    private void longAddChain(boolean reverse) {
+        HighTierContext context = new HighTierContext(getProviders(), null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
+        StructuredGraph graph = new StructuredGraph(AllowAssumptions.NO);
+        ValueNode constant = graph.unique(ConstantNode.forPrimitive(JavaConstant.INT_1));
+        ValueNode value = null;
+        if (reverse) {
+            AddNode addNode = graph.unique(new AddNode(constant, constant));
+            value = addNode;
+            for (int i = 1; i < N; ++i) {
+                AddNode newAddNode = graph.addWithoutUnique(new AddNode(constant, constant));
+                addNode.setY(newAddNode);
+                addNode = newAddNode;
+            }
+        } else {
+            value = constant;
+            for (int i = 0; i < N; ++i) {
+                value = graph.unique(new AddNode(constant, value));
+            }
+        }
+        ReturnNode returnNode = graph.add(new ReturnNode(value));
+        graph.start().setNext(returnNode);
+
+        for (SchedulingStrategy s : SchedulingStrategy.values()) {
+            new SchedulePhase(s).apply(graph);
+        }
+
+        new CanonicalizerPhase(false).apply(graph, context);
+        JavaConstant asConstant = (JavaConstant) returnNode.result().asConstant();
+        Assert.assertEquals(N + 1, asConstant.asInt());
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MergeCanonicalizerTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -61,6 +61,6 @@
         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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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);
     }
@@ -85,7 +85,7 @@
 
     private StructuredGraph parseAndProcess(String snippet) {
         StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
-        ParameterNode param = graph.getNodes(ParameterNode.class).first();
+        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()) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NestedLoopTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -137,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();
             }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/NodePosIteratorTest.java	Mon Mar 02 19:11:22 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/PushThroughIfTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/PushThroughIfTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -59,7 +59,7 @@
     private void test(String snippet, String reference) {
         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);
         }
@@ -67,7 +67,7 @@
         new CanonicalizerPhase(true).apply(graph, new PhaseContext(getProviders()));
 
         StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES);
-        for (FrameState fs : referenceGraph.getNodes(FrameState.class).snapshot()) {
+        for (FrameState fs : referenceGraph.getNodes(FrameState.TYPE).snapshot()) {
             fs.replaceAtUsages(null);
             GraphUtil.killWithUnusedFloatingInputs(fs);
         }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ReadAfterCheckCastTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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/SchedulingTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SchedulingTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -66,7 +66,7 @@
         for (BinaryArithmeticNode<?> node : graph.getNodes().filter(BinaryArithmeticNode.class)) {
             if (!(node instanceof AddNode)) {
                 assertTrue(nodeToBlock.get(node) == nodeToBlock.get(loopExit));
-                assertTrue(list.indexOf(node) < list.indexOf(loopExit));
+                assertTrue(list.indexOf(node) + " < " + list.indexOf(loopExit) + ", " + node + ", " + loopExit, list.indexOf(node) < list.indexOf(loopExit));
             }
         }
     }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -43,8 +43,8 @@
     public void testImplies() {
         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/backend/AllocatorTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/backend/AllocatorTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -64,7 +64,7 @@
         public RegisterStats(LIR lir) {
             this.lir = lir;
 
-            for (AbstractBlock<?> block : lir.codeEmittingOrder()) {
+            for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
                 for (LIRInstruction instr : lir.getLIRforBlock(block)) {
                     collectStats(instr);
                 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -158,7 +158,7 @@
             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/IterativeInliningTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/IterativeInliningTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -79,8 +79,8 @@
 
     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) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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,8 +239,8 @@
 
     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) {
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -66,7 +66,7 @@
             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/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Mar 02 19:11:22 2015 +0100
@@ -44,9 +44,9 @@
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.lir.phases.LIRHighTierPhase.LIRHighTierContext;
-import com.oracle.graal.lir.phases.LIRLowTierPhase.LIRLowTierContext;
-import com.oracle.graal.lir.phases.LIRMidTierPhase.LIRMidTierContext;
+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.*;
@@ -340,7 +340,7 @@
                 throw Debug.handle(e);
             }
 
-            try (Scope s = Debug.scope("LIRTier", nodeLirGen)) {
+            try (Scope s = Debug.scope("LIRStages", nodeLirGen)) {
                 return emitLowLevel(target, codeEmittingOrder, linearScanOrder, lirGenRes, lirGen, lirSuites);
             } catch (Throwable e) {
                 throw Debug.handle(e);
@@ -350,16 +350,16 @@
         }
     }
 
-    public static <T extends AbstractBlock<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
+    public static <T extends AbstractBlockBase<T>> LIRGenerationResult emitLowLevel(TargetDescription target, List<T> codeEmittingOrder, List<T> linearScanOrder, LIRGenerationResult lirGenRes,
                     LIRGeneratorTool lirGen, LIRSuites lirSuites) {
-        LIRHighTierContext highTierContext = new LIRHighTierContext(lirGen);
-        lirSuites.getHighTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, highTierContext);
+        PreAllocationOptimizationContext preAllocOptContext = new PreAllocationOptimizationContext(lirGen);
+        lirSuites.getPreAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, preAllocOptContext);
 
-        LIRMidTierContext midTierContext = new LIRMidTierContext();
-        lirSuites.getMidTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, midTierContext);
+        AllocationContext allocContext = new AllocationContext(lirGen.getSpillMoveFactory());
+        lirSuites.getAllocationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, allocContext);
 
-        LIRLowTierContext lowTierContext = new LIRLowTierContext();
-        lirSuites.getLowTier().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, lowTierContext);
+        PostAllocationOptimizationContext postAllocOptContext = new PostAllocationOptimizationContext();
+        lirSuites.getPostAllocationOptimizationStage().apply(target, lirGenRes, codeEmittingOrder, linearScanOrder, postAllocOptContext);
 
         return lirGenRes;
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/DebugInfoBuilder.java	Mon Mar 02 19:11:22 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);
@@ -111,6 +113,7 @@
         }
         objectStates.clear();
 
+        assert frame.validateFormat();
         return newLIRFrameState(exceptionEdge, frame, virtualObjectsArray);
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/InstructionPrinter.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/NodeLIRBuilder.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchProcessor.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchRuleRegistry.java	Mon Mar 02 19:11:22 2015 +0100
@@ -23,8 +23,6 @@
 package com.oracle.graal.compiler.match;
 
 import static com.oracle.graal.compiler.GraalDebugConfig.*;
-import static com.oracle.graal.graph.Edges.Type.*;
-
 import java.util.*;
 import java.util.Map.Entry;
 
@@ -39,41 +37,25 @@
 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);
+            Edges edges = nodeClass.getInputEdges();
             for (int e = 0; e < edges.getDirectCount(); e++) {
                 if (names[i].equals(edges.getName(e))) {
                     result[i] = new Position(edges, e, Node.NOT_ITERABLE);
                 }
             }
             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 +73,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 +101,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 +115,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/match/MatchStatementSet.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/BasicCompilerConfiguration.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,9 +24,9 @@
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.lir.phases.LIRHighTierPhase.*;
-import com.oracle.graal.lir.phases.LIRLowTierPhase.*;
-import com.oracle.graal.lir.phases.LIRMidTierPhase.*;
+import com.oracle.graal.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.*;
 
@@ -45,16 +45,16 @@
         return new LowTier();
     }
 
-    public LIRPhaseSuite<LIRHighTierContext> createLIRHighTier() {
-        return new LIRHighTier();
+    public LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage() {
+        return new PreAllocationOptimizationStage();
     }
 
-    public LIRPhaseSuite<LIRMidTierContext> createLIRMidTier() {
-        return new LIRMidTier();
+    public LIRPhaseSuite<AllocationContext> createAllocationStage() {
+        return new AllocationStage();
     }
 
-    public LIRPhaseSuite<LIRLowTierContext> createLIRLowTier() {
-        return new LIRLowTier();
+    public LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage() {
+        return new PostAllocationOptimizationStage();
     }
 
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/GraphChangeMonitoringPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -22,12 +22,14 @@
  */
 package com.oracle.graal.compiler.phases;
 
+import java.util.*;
 import java.util.stream.*;
 
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graph.Graph.NodeEvent;
 import com.oracle.graal.graph.Graph.NodeEventScope;
+import com.oracle.graal.graph.Node;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.util.*;
@@ -72,7 +74,11 @@
                 Debug.handle(t);
             }
         }
-        if (!listener.getNodes().isEmpty()) {
+        /*
+         * Ignore LogicConstantNode since those are sometimes created and deleted as part of running
+         * a phase.
+         */
+        if (listener.getNodes().stream().filter(e -> !(e instanceof LogicConstantNode)).findFirst().get() != null) {
             /* rerun it on the real graph in a new Debug scope so Dump and Log can find it. */
             listener = new HashSetNodeEventListener();
             try (NodeEventScope s = graph.trackNodeEvents(listener)) {
@@ -81,10 +87,11 @@
                         Debug.dump(BasePhase.PHASE_DUMP_LEVEL, graph, "*** Before phase %s", getName());
                     }
                     super.run(graph, context);
+                    Set<Node> collect = listener.getNodes().stream().filter(e -> !e.isAlive()).filter(e -> !(e instanceof LogicConstantNode)).collect(Collectors.toSet());
                     if (Debug.isDumpEnabled(BasePhase.PHASE_DUMP_LEVEL)) {
-                        Debug.dump(BasePhase.PHASE_DUMP_LEVEL, graph, "*** After phase %s", getName());
+                        Debug.dump(BasePhase.PHASE_DUMP_LEVEL, graph, "*** After phase %s %s", getName(), collect);
                     }
-                    Debug.log("*** %s %s %s\n", message, graph, listener.getNodes().stream().filter(e -> !e.isAlive()).collect(Collectors.toSet()));
+                    Debug.log("*** %s %s %s\n", message, graph, collect);
                 }
             }
         } else {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfigScope.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugConfigScope.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/LogStream.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/TTY.java	Mon Mar 02 19:11:22 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.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeMapTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeUsagesTests.java	Mon Mar 02 19:11:22 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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/NodeValidationChecksTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,71 @@
+/*
+ * 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.test;
+
+import org.junit.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodeinfo.*;
+
+public class NodeValidationChecksTest {
+
+    @NodeInfo
+    static final class TestNode extends Node {
+        public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class);
+
+        @Input TestNode input;
+        @Successor TestNode successor;
+
+        public TestNode(TestNode input, TestNode successor) {
+            super(TYPE);
+            this.input = input;
+            this.successor = successor;
+        }
+    }
+
+    @Test
+    public void testInputNotAlive() {
+        Graph graph = new Graph();
+        TestNode node = new TestNode(null, null);
+        try {
+            graph.add(new TestNode(node, null));
+            Assert.fail("Exception expected.");
+        } catch (IllegalStateException e) {
+            Assert.assertTrue(e.getMessage().contains("Input"));
+            Assert.assertTrue(e.getMessage().contains("not alive"));
+        }
+    }
+
+    @Test
+    public void testSuccessorNotAlive() {
+        Graph graph = new Graph();
+        TestNode node = new TestNode(null, null);
+        try {
+            graph.add(new TestNode(null, node));
+            Assert.fail("Exception expected.");
+        } catch (IllegalStateException e) {
+            Assert.assertTrue(e.getMessage().contains("Successor"));
+            Assert.assertTrue(e.getMessage().contains("not alive"));
+        }
+    }
+}
--- a/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph.test/src/com/oracle/graal/graph/test/TypedNodeIteratorTest2.java	Mon Mar 02 19:11:22 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/Edges.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Edges.java	Mon Mar 02 19:11:22 2015 +0100
@@ -27,6 +27,7 @@
 import static com.oracle.graal.graph.Node.*;
 
 import java.util.*;
+import java.util.function.*;
 
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.NodeClass.EdgeInfo;
@@ -60,20 +61,20 @@
         }
     }
 
-    private static Node getNode(Node node, long offset) {
+    private static Node getNodeUnsafe(Node node, long offset) {
         return (Node) unsafe.getObject(node, offset);
     }
 
     @SuppressWarnings("unchecked")
-    private static NodeList<Node> getNodeList(Node node, long offset) {
+    private static NodeList<Node> getNodeListUnsafe(Node node, long offset) {
         return (NodeList<Node>) unsafe.getObject(node, offset);
     }
 
-    private static void putNode(Node node, long offset, Node value) {
+    private static void putNodeUnsafe(Node node, long offset, Node value) {
         unsafe.putObject(node, offset, value);
     }
 
-    private static void putNodeList(Node node, long offset, NodeList<?> value) {
+    private static void putNodeListUnsafe(Node node, long offset, NodeList<?> value) {
         unsafe.putObject(node, offset, value);
     }
 
@@ -92,9 +93,8 @@
      * @param index the index of a non-list the edge (must be less than {@link #getDirectCount()})
      * @return the Node at the other edge of the requested edge
      */
-    public Node getNode(Node node, int index) {
-        assert index >= 0 && index < directCount;
-        return getNode(node, offsets[index]);
+    public static Node getNode(Node node, long[] offsets, int index) {
+        return getNodeUnsafe(node, offsets[index]);
     }
 
     /**
@@ -105,9 +105,8 @@
      *            {@link #getDirectCount()})
      * @return the {@link NodeList} at the other edge of the requested edge
      */
-    public NodeList<Node> getNodeList(Node node, int index) {
-        assert index >= directCount && index < getCount();
-        return getNodeList(node, offsets[index]);
+    public static NodeList<Node> getNodeList(Node node, long[] offsets, int index) {
+        return getNodeListUnsafe(node, offsets[index]);
     }
 
     /**
@@ -118,18 +117,22 @@
      * @param node the node whose edges are to be cleared
      */
     public void clear(Node node) {
+        final long[] curOffsets = this.offsets;
+        final Type curType = this.type;
         int index = 0;
-        while (index < getDirectCount()) {
-            initializeNode(node, index++, null);
+        int curDirectCount = getDirectCount();
+        while (index < curDirectCount) {
+            initializeNode(node, curOffsets, index++, null);
         }
-        while (index < getCount()) {
-            NodeList<Node> list = getNodeList(node, index);
+        int curCount = getCount();
+        while (index < curCount) {
+            NodeList<Node> list = getNodeList(node, curOffsets, index);
             if (list != null) {
                 int size = list.initialSize;
-                NodeList<Node> newList = type == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
+                NodeList<Node> newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
 
                 // replacing with a new list object is the expected behavior!
-                initializeList(node, index, newList);
+                initializeList(node, curOffsets, index, newList);
             }
             index++;
         }
@@ -144,12 +147,14 @@
      */
     public void initializeLists(Node node, Node prototype) {
         int index = getDirectCount();
+        final long[] curOffsets = this.offsets;
+        final Edges.Type curType = this.type;
         while (index < getCount()) {
-            NodeList<Node> list = getNodeList(prototype, index);
+            NodeList<Node> list = getNodeList(prototype, curOffsets, index);
             if (list != null) {
                 int size = list.initialSize;
-                NodeList<Node> newList = type == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
-                initializeList(node, index, newList);
+                NodeList<Node> newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size);
+                initializeList(node, curOffsets, index, newList);
             }
             index++;
         }
@@ -166,16 +171,20 @@
         assert fromNode != toNode;
         assert fromNode.getNodeClass().getClazz() == toNode.getNodeClass().getClazz();
         int index = 0;
-        while (index < getDirectCount()) {
-            initializeNode(toNode, index, getNode(fromNode, index));
+        final long[] curOffsets = this.offsets;
+        final Type curType = this.type;
+        int curDirectCount = getDirectCount();
+        while (index < curDirectCount) {
+            initializeNode(toNode, curOffsets, index, getNode(fromNode, curOffsets, index));
             index++;
         }
-        while (index < getCount()) {
-            NodeList<Node> list = getNodeList(toNode, index);
-            NodeList<Node> fromList = getNodeList(fromNode, index);
+        int curCount = getCount();
+        while (index < curCount) {
+            NodeList<Node> list = getNodeList(toNode, curOffsets, index);
+            NodeList<Node> fromList = getNodeList(fromNode, curOffsets, index);
             if (list == null || list == fromList) {
-                list = type == Edges.Type.Inputs ? new NodeInputList<>(toNode, fromList) : new NodeSuccessorList<>(toNode, fromList);
-                initializeList(toNode, index, list);
+                list = curType == Edges.Type.Inputs ? new NodeInputList<>(toNode, fromList) : new NodeSuccessorList<>(toNode, fromList);
+                initializeList(toNode, curOffsets, index, list);
             } else {
                 list.copy(fromList);
             }
@@ -194,17 +203,20 @@
      */
     public boolean replaceFirst(Node node, Node key, Node replacement) {
         int index = 0;
-        while (index < getDirectCount()) {
-            Node edge = getNode(node, index);
+        final long[] curOffsets = this.getOffsets();
+        int curDirectCount = getDirectCount();
+        while (index < curDirectCount) {
+            Node edge = getNode(node, curOffsets, index);
             if (edge == key) {
                 assert replacement == null || getType(index).isAssignableFrom(replacement.getClass()) : "Can not assign " + replacement.getClass() + " to " + getType(index) + " in " + node;
-                initializeNode(node, index, replacement);
+                initializeNode(node, curOffsets, index, replacement);
                 return true;
             }
             index++;
         }
-        while (index < getCount()) {
-            NodeList<Node> list = getNodeList(node, index);
+        int curCount = getCount();
+        while (index < curCount) {
+            NodeList<Node> list = getNodeList(node, curOffsets, index);
             if (list != null) {
                 if (list.replaceFirst(key, replacement)) {
                     return true;
@@ -228,13 +240,12 @@
      * @param index the index of the edge (between 0 and {@link #getCount()})
      * @param value the node to be written to the edge
      */
-    public void initializeNode(Node node, int index, Node value) {
-        putNode(node, offsets[index], value);
+    public static void initializeNode(Node node, long[] offsets, int index, Node value) {
+        putNodeUnsafe(node, offsets[index], value);
     }
 
-    public void initializeList(Node node, int index, NodeList<Node> value) {
-        assert index >= directCount;
-        putNodeList(node, offsets[index], value);
+    public static void initializeList(Node node, long[] offsets, int index, NodeList<Node> value) {
+        putNodeListUnsafe(node, offsets[index], value);
     }
 
     /**
@@ -247,21 +258,22 @@
      */
     public void setNode(Node node, int index, Node value) {
         assert index < directCount;
-        Node old = getNode(node, offsets[index]);
-        putNode(node, offsets[index], value);
+        Node old = getNodeUnsafe(node, offsets[index]);
+        putNodeUnsafe(node, offsets[index], value);
         update(node, old, value);
     }
 
     protected abstract void update(Node node, Node oldValue, Node newValue);
 
     public boolean contains(Node node, Node value) {
+        final long[] curOffsets = this.offsets;
         for (int i = 0; i < directCount; i++) {
-            if (getNode(node, i) == value) {
+            if (getNode(node, curOffsets, i) == value) {
                 return true;
             }
         }
         for (int i = directCount; i < getCount(); i++) {
-            NodeList<?> curList = getNodeList(node, i);
+            NodeList<?> curList = getNodeList(node, curOffsets, i);
             if (curList != null && curList.contains(value)) {
                 return true;
             }
@@ -275,15 +287,16 @@
     public boolean areEqualIn(Node node, Node other) {
         assert node.getNodeClass().getClazz() == other.getNodeClass().getClazz();
         int index = 0;
+        final long[] curOffsets = this.offsets;
         while (index < directCount) {
-            if (getNode(other, index) != getNode(node, index)) {
+            if (getNode(other, curOffsets, index) != getNode(node, curOffsets, index)) {
                 return false;
             }
             index++;
         }
         while (index < getCount()) {
-            NodeList<Node> list = getNodeList(other, index);
-            if (!Objects.equals(list, getNodeList(node, index))) {
+            NodeList<Node> list = getNodeList(other, curOffsets, index);
+            if (!Objects.equals(list, getNodeList(node, curOffsets, index))) {
                 return false;
             }
             index++;
@@ -305,6 +318,9 @@
         NodeList<Node> list;
         protected boolean needsForward;
         protected Node nextElement;
+        protected final int directCount;
+        protected final int count;
+        protected final long[] offsets;
 
         /**
          * Creates an iterator that will iterate over some given edges in a given node.
@@ -315,14 +331,17 @@
             index = NOT_ITERABLE;
             subIndex = 0;
             needsForward = true;
+            this.directCount = edges.getDirectCount();
+            this.offsets = edges.getOffsets();
+            this.count = edges.getCount();
         }
 
         void forward() {
             needsForward = false;
-            if (index < edges.getDirectCount()) {
+            if (index < directCount) {
                 index++;
-                while (index < edges.getDirectCount()) {
-                    nextElement = edges.getNode(node, index);
+                while (index < directCount) {
+                    nextElement = Edges.getNode(node, offsets, index);
                     if (nextElement != null) {
                         return;
                     }
@@ -339,7 +358,7 @@
         private void forwardNodeList() {
             do {
                 if (subIndex == 0) {
-                    list = edges.getNodeList(node, index);
+                    list = Edges.getNodeList(node, offsets, index);
                 }
                 if (list != null) {
                     while (subIndex < list.size()) {
@@ -360,7 +379,7 @@
                 forward();
             }
             needsForward = true;
-            if (index < edges.getCount()) {
+            if (index < count) {
                 return nextElement;
             }
             throw new NoSuchElementException();
@@ -384,7 +403,7 @@
                 forward();
             }
             needsForward = true;
-            if (index < edges.getDirectCount()) {
+            if (index < directCount) {
                 return new Position(edges, index, NOT_ITERABLE);
             } else {
                 return new Position(edges, index, subIndex);
@@ -398,6 +417,7 @@
     }
 
     private static class AllEdgesIterator extends EdgesIterator {
+
         AllEdgesIterator(Node node, Edges edges) {
             super(node, edges);
         }
@@ -405,10 +425,10 @@
         @Override
         void forward() {
             needsForward = false;
-            if (index < edges.getDirectCount()) {
+            if (index < directCount) {
                 index++;
                 if (index < edges.getDirectCount()) {
-                    nextElement = edges.getNode(node, index);
+                    nextElement = Edges.getNode(node, edges.getOffsets(), index);
                     return;
                 }
             } else {
@@ -416,7 +436,7 @@
             }
             while (index < edges.getCount()) {
                 if (subIndex == 0) {
-                    list = edges.getNodeList(node, index);
+                    list = Edges.getNodeList(node, edges.getOffsets(), index);
                 }
                 if (list != null) {
                     if (subIndex < list.size()) {
@@ -467,6 +487,9 @@
         }
     }
 
+    static int cnt1;
+    static int cnt2;
+
     public NodeClassIterable getIterable(final Node node) {
         return new NodeClassIterable() {
 
@@ -493,4 +516,34 @@
     public Type type() {
         return type;
     }
+
+    public void accept(Node node, BiConsumer<Node, Node> consumer) {
+        int index = 0;
+        int curDirectCount = this.directCount;
+        final long[] curOffsets = this.offsets;
+        while (index < curDirectCount) {
+            Node curNode = getNode(node, curOffsets, index);
+            if (curNode != null) {
+                consumer.accept(node, curNode);
+            }
+            index++;
+        }
+        int count = getCount();
+        while (index < count) {
+            NodeList<Node> list = getNodeList(node, curOffsets, index);
+            if (list != null) {
+                for (int i = 0; i < list.size(); ++i) {
+                    Node curNode = list.get(i);
+                    if (curNode != null) {
+                        consumer.accept(node, curNode);
+                    }
+                }
+            }
+            index++;
+        }
+    }
+
+    public long[] getOffsets() {
+        return this.offsets;
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Mar 02 19:11:22 2015 +0100
@@ -452,18 +452,17 @@
         return uniqueHelper(node, true);
     }
 
-    @SuppressWarnings("unchecked")
     <T extends Node> T uniqueHelper(T node, boolean addIfMissing) {
         assert node.getNodeClass().valueNumberable();
-        Node other = this.findDuplicate(node);
+        T other = this.findDuplicate(node);
         if (other != null) {
-            return (T) other;
+            return other;
         } else {
-            Node result = addIfMissing ? addHelper(node) : node;
+            T result = addIfMissing ? addHelper(node) : node;
             if (node.getNodeClass().isLeafNode()) {
                 putNodeIntoCache(result);
             }
-            return (T) result;
+            return result;
         }
     }
 
@@ -484,41 +483,45 @@
         return result;
     }
 
-    public Node findDuplicate(Node node) {
-        NodeClass nodeClass = node.getNodeClass();
+    @SuppressWarnings("unchecked")
+    public <T extends Node> T findDuplicate(T node) {
+        NodeClass<?> nodeClass = node.getNodeClass();
         assert nodeClass.valueNumberable();
         if (nodeClass.isLeafNode()) {
             // Leaf node: look up in cache
             Node cachedNode = findNodeInCache(node);
             if (cachedNode != null) {
-                return cachedNode;
+                return (T) cachedNode;
             } else {
                 return null;
             }
         } else {
-            // Non-leaf node: look for another usage of the node's inputs that
-            // has the same data, inputs and successors as the node. To reduce
-            // the cost of this computation, only the input with estimated highest
-            // usage count is considered.
-
+            /*
+             * Non-leaf node: look for another usage of the node's inputs that has the same data,
+             * inputs and successors as the node. To reduce the cost of this computation, only the
+             * input with lowest usage count is considered. If this node is the only user of any
+             * input then the search can terminate early. The usage count is only incremented once
+             * the Node is in the Graph, so account for that in the test.
+             */
+            final int earlyExitUsageCount = node.graph() != null ? 1 : 0;
             int minCount = Integer.MAX_VALUE;
             Node minCountNode = null;
             for (Node input : node.inputs()) {
                 if (input != null) {
-                    int estimate = input.getUsageCount();
-                    if (estimate == 0) {
+                    int usageCount = input.getUsageCount();
+                    if (usageCount == earlyExitUsageCount) {
                         return null;
-                    } else if (estimate < minCount) {
-                        minCount = estimate;
+                    } else if (usageCount < minCount) {
+                        minCount = usageCount;
                         minCountNode = input;
                     }
                 }
             }
             if (minCountNode != null) {
                 for (Node usage : minCountNode.usages()) {
-                    if (usage != node && nodeClass == usage.getNodeClass() && node.valueEquals(usage) && nodeClass.getEdges(Inputs).areEqualIn(node, usage) &&
+                    if (usage != node && nodeClass == usage.getNodeClass() && node.valueEquals(usage) && nodeClass.getInputEdges().areEqualIn(node, usage) &&
                                     nodeClass.getEdges(Successors).areEqualIn(node, usage)) {
-                        return usage;
+                        return (T) usage;
                     }
                 }
                 return null;
@@ -625,7 +628,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 +692,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 +711,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 +744,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 +769,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();
@@ -819,8 +828,8 @@
         return true;
     }
 
-    Node getNode(int i) {
-        return nodes[i];
+    public Node getNode(int id) {
+        return nodes[id];
     }
 
     /**
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/IterableNodeType.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/IterableNodeType.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Mar 02 19:11:22 2015 +0100
@@ -27,6 +27,7 @@
 
 import java.lang.annotation.*;
 import java.util.*;
+import java.util.function.*;
 
 import sun.misc.*;
 
@@ -76,6 +77,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 +162,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 +203,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() {
@@ -276,7 +287,16 @@
      * @return an {@link NodeClassIterable iterable} for all non-null input edges.
      */
     public NodeClassIterable inputs() {
-        return getNodeClass().getEdges(Inputs).getIterable(this);
+        return nodeClass.getInputEdges().getIterable(this);
+    }
+
+    /**
+     * Applies the given consumer to all inputs of this node.
+     *
+     * @param consumer the consumer to be applied to the inputs
+     */
+    public void acceptInputs(BiConsumer<Node, Node> consumer) {
+        nodeClass.getInputEdges().accept(this, consumer);
     }
 
     /**
@@ -286,7 +306,16 @@
      * @return an {@link NodeClassIterable iterable} for all non-null successor edges.
      */
     public NodeClassIterable successors() {
-        return getNodeClass().getEdges(Successors).getIterable(this);
+        return nodeClass.getSuccessorEdges().getIterable(this);
+    }
+
+    /**
+     * Applies the given consumer to all successors of this node.
+     *
+     * @param consumer the consumer to be applied to the inputs
+     */
+    public void acceptSuccessors(BiConsumer<Node, Node> consumer) {
+        nodeClass.getSuccessorEdges().accept(this, consumer);
     }
 
     /**
@@ -332,7 +361,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;
         }
@@ -371,7 +402,7 @@
      * @param node the node to remove
      * @return whether or not {@code usage} was in the usage list
      */
-    private boolean removeUsage(Node node) {
+    public boolean removeUsage(Node node) {
         assert node != null;
         // It is critical that this method maintains the invariant that
         // the usage list has no null element preceding a non-null element
@@ -395,6 +426,7 @@
 
     private void clearUsages() {
         incUsageModCount();
+        maybeNotifyZeroUsages(this);
         usage0 = null;
         usage1 = null;
         extraUsages = NO_NODES;
@@ -489,15 +521,21 @@
         assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id);
         this.graph = newGraph;
         newGraph.register(this);
-        for (Node input : inputs()) {
-            updateUsages(null, input);
-        }
-        for (Node successor : successors()) {
-            updatePredecessor(null, successor);
-        }
+        this.acceptInputs((n, i) -> {
+            if (!i.isAlive()) {
+                throw new IllegalStateException(String.format("Input %s of newly created node %s is not alive.", i, n));
+            }
+            n.updateUsages(null, i);
+        });
+        this.acceptSuccessors((n, s) -> {
+            if (!s.isAlive()) {
+                throw new IllegalStateException(String.format("Successor %s of newly created node %s is not alive.", s, n));
+            }
+            n.updatePredecessor(null, s);
+        });
     }
 
-    public final NodeClass getNodeClass() {
+    public final NodeClass<? extends Node> getNodeClass() {
         return nodeClass;
     }
 
@@ -516,7 +554,7 @@
     public void replaceAtUsages(Node other) {
         assert checkReplaceWith(other);
         for (Node usage : usages()) {
-            boolean result = usage.getNodeClass().getEdges(Inputs).replaceFirst(usage, this, other);
+            boolean result = usage.getNodeClass().getInputEdges().replaceFirst(usage, this, other);
             assert assertTrue(result, "not found in inputs, usage: %s", usage);
             if (other != null) {
                 maybeNotifyInputChanged(usage);
@@ -542,7 +580,7 @@
         while (index < this.getUsageCount()) {
             Node usage = getUsageAt(index);
             if (usagePredicate.apply(usage)) {
-                boolean result = usage.getNodeClass().getEdges(Inputs).replaceFirst(usage, this, other);
+                boolean result = usage.getNodeClass().getInputEdges().replaceFirst(usage, this, other);
                 assert assertTrue(result, "not found in inputs, usage: %s", usage);
                 if (other != null) {
                     maybeNotifyInputChanged(usage);
@@ -585,7 +623,7 @@
         if (graph != null) {
             assert !graph.isFrozen();
             NodeEventListener listener = graph.nodeEventListener;
-            if (listener != null) {
+            if (listener != null && node.isAlive()) {
                 listener.usagesDroppedToZero(node);
             }
             if (Fingerprint.ENABLED) {
@@ -597,7 +635,7 @@
     public void replaceAtPredecessor(Node other) {
         assert checkReplaceWith(other);
         if (predecessor != null) {
-            boolean result = predecessor.getNodeClass().getEdges(Successors).replaceFirst(predecessor, this, other);
+            boolean result = predecessor.getNodeClass().getSuccessorEdges().replaceFirst(predecessor, this, other);
             assert assertTrue(result, "not found in successors, predecessor: %s", predecessor);
             predecessor.updatePredecessor(this, other);
         }
@@ -605,22 +643,22 @@
 
     public void replaceAndDelete(Node other) {
         assert checkReplaceWith(other);
-        if (other != null) {
-            clearSuccessors();
-            replaceAtUsages(other);
-            replaceAtPredecessor(other);
-        }
+        assert other != null;
+        clearInputs();
+        clearSuccessors();
+        replaceAtUsages(other);
+        replaceAtPredecessor(other);
         safeDelete();
     }
 
     public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) {
-        if (getNodeClass().getEdges(Successors).replaceFirst(this, oldSuccessor, newSuccessor)) {
+        if (nodeClass.getSuccessorEdges().replaceFirst(this, oldSuccessor, newSuccessor)) {
             updatePredecessor(oldSuccessor, newSuccessor);
         }
     }
 
     public void replaceFirstInput(Node oldInput, Node newInput) {
-        if (getNodeClass().getEdges(Inputs).replaceFirst(this, oldInput, newInput)) {
+        if (nodeClass.getInputEdges().replaceFirst(this, oldInput, newInput)) {
             updateUsages(oldInput, newInput);
         }
     }
@@ -638,7 +676,7 @@
         assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
 
         unregisterInputs();
-        getNodeClass().getEdges(Inputs).clear(this);
+        getNodeClass().getInputEdges().clear(this);
     }
 
     private boolean removeThisFromUsages(Node n) {
@@ -646,17 +684,14 @@
     }
 
     private void unregisterSuccessors() {
-        for (Node successor : successors()) {
-            assert assertTrue(successor.predecessor == this, "wrong predecessor in old successor (%s): %s", successor, successor.predecessor);
-            successor.predecessor = null;
-        }
+        this.acceptSuccessors((n, successor) -> successor.predecessor = null);
     }
 
     public void clearSuccessors() {
         assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
 
         unregisterSuccessors();
-        getNodeClass().getEdges(Successors).clear(this);
+        getNodeClass().getSuccessorEdges().clear(this);
     }
 
     private boolean checkDeletion() {
@@ -673,6 +708,10 @@
         assert checkDeletion();
         unregisterInputs();
         unregisterSuccessors();
+        markDeleted();
+    }
+
+    public void markDeleted() {
         graph.unregister(this);
         id = DELETED_ID_START - id;
         assert isDeleted();
@@ -739,7 +778,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/NodeBitMap.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeBitMap.java	Mon Mar 02 19:11:22 2015 +0100
@@ -60,6 +60,10 @@
     public boolean isMarked(Node node) {
         assert check(node, false);
         int id = nodeIdAccessor.getNodeId(node);
+        return isMarked(id);
+    }
+
+    public boolean isMarked(int id) {
         return (bits[id >> SHIFT] & (1L << id)) != 0;
     }
 
@@ -67,7 +71,7 @@
         assert check(node, true);
         int id = nodeIdAccessor.getNodeId(node);
         checkGrow(id);
-        return (bits[id >> SHIFT] & (1L << id)) != 0;
+        return isMarked(id);
     }
 
     public void mark(Node node) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Mar 02 19:11:22 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.*;
@@ -40,6 +41,7 @@
 import com.oracle.graal.graph.Node.OptionalInput;
 import com.oracle.graal.graph.Node.Successor;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.nodeinfo.*;
 
 /**
@@ -50,12 +52,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 +72,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;
@@ -129,21 +119,27 @@
     private final boolean isCanonicalizable;
 
     /**
+     * Determines if this node type implements {@link BinaryCommutative}.
+     */
+    private final boolean isCommutative;
+
+    /**
      * Determines if this node type implements {@link Simplifiable}.
      */
     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);
 
         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
+        this.isCommutative = BinaryCommutative.class.isAssignableFrom(clazz);
         if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) {
             assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both";
         }
@@ -183,9 +179,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);
@@ -249,6 +245,13 @@
     }
 
     /**
+     * Determines if this node type implements {@link BinaryCommutative}.
+     */
+    public boolean isCommutative() {
+        return isCommutative;
+    }
+
+    /**
      * Determines if this node type implements {@link Simplifiable}.
      */
     public boolean isSimplifiable() {
@@ -256,7 +259,7 @@
     }
 
     static int allocatedNodeIterabledIds() {
-        return nextIterableId;
+        return nextIterableId.get();
     }
 
     public EnumSet<InputType> getAllowedUsageTypes() {
@@ -316,7 +319,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 +567,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;
         }
@@ -580,30 +583,38 @@
 
     static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) {
         int index = 0;
-        while (index < edges.getDirectCount()) {
-            Node edge = edges.getNode(node, index);
+        Type curType = edges.type();
+        int directCount = edges.getDirectCount();
+        final long[] curOffsets = edges.getOffsets();
+        while (index < directCount) {
+            Node edge = Edges.getNode(node, curOffsets, index);
             if (edge != null) {
-                Node newEdge = duplicationReplacement.replacement(edge, edges.type());
-                if (edges.type() == Edges.Type.Inputs) {
+                Node newEdge = duplicationReplacement.replacement(edge, curType);
+                if (curType == Edges.Type.Inputs) {
                     node.updateUsages(null, newEdge);
                 } else {
                     node.updatePredecessor(null, newEdge);
                 }
-                assert newEdge == null || edges.getType(index).isAssignableFrom(newEdge.getClass()) : "Can not assign " + newEdge.getClass() + " to " + edges.getType(index) + " in " + node;
-                edges.initializeNode(node, index, newEdge);
+                assert assertUpdateValid(node, edges, index, newEdge);
+                Edges.initializeNode(node, curOffsets, index, newEdge);
             }
             index++;
         }
 
         while (index < edges.getCount()) {
-            NodeList<Node> list = edges.getNodeList(node, index);
+            NodeList<Node> list = Edges.getNodeList(node, curOffsets, index);
             if (list != null) {
-                edges.initializeList(node, index, updateEdgeListCopy(node, list, duplicationReplacement, edges.type()));
+                Edges.initializeList(node, curOffsets, index, updateEdgeListCopy(node, list, duplicationReplacement, curType));
             }
             index++;
         }
     }
 
+    private static boolean assertUpdateValid(Node node, Edges edges, int index, Node newEdge) {
+        assert newEdge == null || edges.getType(index).isAssignableFrom(newEdge.getClass()) : "Can not assign " + newEdge.getClass() + " to " + edges.getType(index) + " in " + node;
+        return true;
+    }
+
     void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) {
         updateEdgesInPlace(node, duplicationReplacement, inputs);
         updateEdgesInPlace(node, duplicationReplacement, successors);
@@ -629,6 +640,14 @@
         return type == Edges.Type.Inputs ? inputs : successors;
     }
 
+    public Edges getInputEdges() {
+        return inputs;
+    }
+
+    public Edges getSuccessorEdges() {
+        return successors;
+    }
+
     /**
      * Initializes a fresh allocated node for which no constructor is called yet. Needed to
      * implement node factories in svm.
@@ -641,14 +660,15 @@
 
     private void initNullEdgeLists(Node node, Edges.Type type) {
         Edges edges = getEdges(type);
+        final long[] curOffsets = edges.getOffsets();
         for (int inputPos = edges.getDirectCount(); inputPos < edges.getCount(); inputPos++) {
-            if (edges.getNodeList(node, inputPos) == null) {
-                edges.initializeList(node, inputPos, type == Edges.Type.Inputs ? new NodeInputList<>(node) : new NodeSuccessorList<>(node));
+            if (Edges.getNodeList(node, curOffsets, inputPos) == null) {
+                Edges.initializeList(node, curOffsets, inputPos, type == Edges.Type.Inputs ? new NodeInputList<>(node) : new NodeSuccessorList<>(node));
             }
         }
     }
 
-    public Class<?> getJavaClass() {
+    public Class<T> getJavaClass() {
         return getClazz();
     }
 
@@ -702,7 +722,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 +766,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/NodeFlood.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeFlood.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,10 +24,11 @@
 
 import java.util.*;
 
-public class NodeFlood implements Iterable<Node> {
+public final class NodeFlood implements Iterable<Node> {
 
     private final NodeBitMap visited;
     private final Queue<Node> worklist;
+    private int totalMarkedCount;
 
     public NodeFlood(Graph graph) {
         visited = graph.createNodeBitMap();
@@ -38,15 +39,24 @@
         if (node != null && !visited.isMarked(node)) {
             visited.mark(node);
             worklist.add(node);
+            totalMarkedCount++;
         }
     }
 
+    public int getTotalMarkedCount() {
+        return totalMarkedCount;
+    }
+
     public void addAll(Iterable<? extends Node> nodes) {
         for (Node node : nodes) {
             this.add(node);
         }
     }
 
+    public NodeBitMap getVisited() {
+        return visited;
+    }
+
     public boolean isMarked(Node node) {
         return visited.isMarked(node);
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeIdAccessor.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeIdAccessor.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Mar 02 19:11:22 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;
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUnionFind.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeUnionFind.java	Mon Mar 02 19:11:22 2015 +0100
@@ -73,12 +73,14 @@
     private void union(int a, int b) {
         int aRoot = find(a);
         int bRoot = find(b);
-        if (rank[aRoot] < rank[bRoot]) {
-            parent[aRoot] = bRoot;
-        } else {
-            parent[bRoot] = aRoot;
-            if (rank[aRoot] == rank[bRoot]) {
-                rank[aRoot]++;
+        if (aRoot != bRoot) {
+            if (rank[aRoot] < rank[bRoot]) {
+                parent[aRoot] = bRoot;
+            } else {
+                parent[bRoot] = aRoot;
+                if (rank[aRoot] == rank[bRoot]) {
+                    rank[aRoot]++;
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeWorkList.java	Mon Mar 02 19:11:22 2015 +0100
@@ -157,7 +157,7 @@
         }
 
         private boolean checkInfiniteWork(Node node) {
-            if (lastPull == node) {
+            if (lastPull == node && !node.hasNoUsages()) {
                 if (firstNoChange == null) {
                     firstNoChange = node;
                     lastChain = node;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Position.java	Mon Mar 02 19:11:22 2015 +0100
@@ -53,9 +53,9 @@
 
     public Node get(Node node) {
         if (index < edges.getDirectCount()) {
-            return edges.getNode(node, index);
+            return Edges.getNode(node, edges.getOffsets(), index);
         } else {
-            return edges.getNodeList(node, index).get(subIndex);
+            return Edges.getNodeList(node, edges.getOffsets(), index).get(subIndex);
         }
     }
 
@@ -75,15 +75,15 @@
         if (index < edges.getDirectCount()) {
             edges.setNode(node, index, value);
         } else {
-            edges.getNodeList(node, index).set(subIndex, value);
+            Edges.getNodeList(node, edges.getOffsets(), index).set(subIndex, value);
         }
     }
 
     public void initialize(Node node, Node value) {
         if (index < edges.getDirectCount()) {
-            edges.initializeNode(node, index, value);
+            Edges.initializeNode(node, edges.getOffsets(), index, value);
         } else {
-            edges.getNodeList(node, index).initialize(subIndex, value);
+            Edges.getNodeList(node, edges.getOffsets(), index).initialize(subIndex, value);
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/TypedGraphNodeIterator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/TypedGraphNodeIterator.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/VerificationError.java	Mon Mar 02 19:11:22 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/Canonicalizable.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/Canonicalizable.java	Mon Mar 02 19:11:22 2015 +0100
@@ -128,4 +128,22 @@
             return canonical(tool, getX(), getY());
         }
     }
+
+    /**
+     * This sub-interface of {@link Canonicalizable.Binary} is for nodes with two inputs where the
+     * operation is commutative. It is used to improve GVN by trying to merge nodes with the same
+     * inputs in different order.
+     */
+    public interface BinaryCommutative<T extends Node> extends Binary<T> {
+
+        /**
+         * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order
+         * the inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on
+         * the node if it's currently in a graph. It's assumed that if there was a constant on the
+         * left it's been moved to the right by other code and that ordering is left alone.
+         *
+         * @return the original node or another node with the same input ordering
+         */
+        Node maybeCommuteInputs();
+    }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/Simplifiable.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/spi/Simplifiable.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64.test/src/com/oracle/graal/hotspot/amd64/test/DataPatchInConstantsTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64DeoptimizeOp.java	Mon Mar 02 19:11:22 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/AMD64HotSpotBackendFactory.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java	Mon Mar 02 19:11:22 2015 +0100
@@ -163,7 +163,7 @@
                 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);
         }
@@ -209,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) {
@@ -248,15 +248,15 @@
         } else {
             /*
              * System V Application Binary Interface, AMD64 Architecture Processor Supplement
-             * 
+             *
              * Draft Version 0.96
-             * 
+             *
              * http://www.uclibc.org/docs/psABI-x86_64.pdf
-             * 
+             *
              * 3.2.1
-             * 
+             *
              * ...
-             * 
+             *
              * This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
              * through %r15 "belong" to the calling function and the called function is required to
              * preserve their values. In other words, a called function must preserve these
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallEpilogueOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCRuntimeCallPrologueOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableAddressOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCardTableShiftOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompare.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotDeoptimizeCallerOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEnterUnpackFramesStackFrameOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotEpilogueOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotJumpToExceptionHandlerInCallerOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveCurrentStackFrameOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveDeoptimizedStackFrameOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLeaveUnpackFramesStackFrameOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPatchReturnAddressOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotPushInterpreterFrameOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotReturnOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotSafepointOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotUnwindOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectStaticCallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64IndirectCallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64PrefetchOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64RawNativeCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64TailcallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.server/src/com/oracle/graal/hotspot/server/InvocationSocket.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCDeoptimizeOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Mon Mar 02 19:11:22 2015 +0100
@@ -269,7 +269,7 @@
     }
 
     private static void resetDelayedControlTransfers(LIR lir) {
-        for (AbstractBlock<?> block : lir.codeEmittingOrder()) {
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
             for (LIRInstruction inst : lir.getLIRforBlock(block)) {
                 if (inst instanceof SPARCDelayedControlTransfer) {
                     ((SPARCDelayedControlTransfer) inst).resetState();
@@ -281,11 +281,11 @@
     /**
      * Fix-up over whole LIR.
      *
-     * @see #stuffDelayedControlTransfers(LIR, AbstractBlock)
+     * @see #stuffDelayedControlTransfers(LIR, AbstractBlockBase)
      * @param l
      */
     private static void stuffDelayedControlTransfers(LIR l) {
-        for (AbstractBlock<?> b : l.codeEmittingOrder()) {
+        for (AbstractBlockBase<?> b : l.codeEmittingOrder()) {
             stuffDelayedControlTransfers(l, b);
         }
     }
@@ -295,7 +295,7 @@
      * it tries to move the DelayedLIRInstruction to the DelayedControlTransfer instruction, if
      * possible.
      */
-    private static void stuffDelayedControlTransfers(LIR l, AbstractBlock<?> block) {
+    private static void stuffDelayedControlTransfers(LIR l, AbstractBlockBase<?> block) {
         List<LIRInstruction> instructions = l.getLIRforBlock(block);
         if (instructions.size() >= 2) {
             LIRDependencyAccumulator acc = new LIRDependencyAccumulator();
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java	Mon Mar 02 19:11:22 2015 +0100
@@ -64,7 +64,7 @@
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime);
         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);
@@ -93,10 +93,14 @@
 
     @SuppressWarnings("unused")
     private static Value[] createNativeABICallerSaveRegisters(HotSpotVMConfig config, RegisterConfig regConfig) {
-        CalleeSaveLayout csl = regConfig.getCalleeSaveLayout();
-        Value[] nativeABICallerSaveRegisters = new Value[csl.registers.length];
-        for (int i = 0; i < csl.registers.length; i++) {
-            nativeABICallerSaveRegisters[i] = csl.registers[i].asValue();
+        Set<Register> callerSavedRegisters = new HashSet<>();
+        Collections.addAll(callerSavedRegisters, regConfig.getCalleeSaveLayout().registers);
+        Collections.addAll(callerSavedRegisters, SPARC.fpuRegisters);
+        Value[] nativeABICallerSaveRegisters = new Value[callerSavedRegisters.size()];
+        int i = 0;
+        for (Register reg : callerSavedRegisters) {
+            nativeABICallerSaveRegisters[i] = reg.asValue();
+            i++;
         }
         return nativeABICallerSaveRegisters;
     }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallEpilogueOp.java	Mon Mar 02 19:11:22 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
@@ -34,6 +34,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;
@@ -42,6 +43,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCRuntimeCallPrologueOp.java	Mon Mar 02 19:11:22 2015 +0100
@@ -34,6 +34,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;
@@ -41,6 +42,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEnterUnpackFramesStackFrameOp.java	Mon Mar 02 19:11:22 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
@@ -40,6 +40,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;
@@ -49,6 +50,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotEpilogueOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotForeignCallsProvider.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java	Mon Mar 02 19:11:22 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
@@ -42,6 +42,8 @@
 @Opcode("JUMP_TO_EXCEPTION_HANDLER_IN_CALLER")
 final class SPARCHotSpotJumpToExceptionHandlerInCallerOp extends SPARCHotSpotEpilogueOp {
 
+    public static final LIRInstructionClass<SPARCHotSpotJumpToExceptionHandlerInCallerOp> TYPE = LIRInstructionClass.create(SPARCHotSpotJumpToExceptionHandlerInCallerOp.class);
+
     @Use(REG) AllocatableValue handlerInCallerPc;
     @Use(REG) AllocatableValue exception;
     @Use(REG) AllocatableValue exceptionPc;
@@ -49,6 +51,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveCurrentStackFrameOp.java	Mon Mar 02 19:11:22 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,8 +34,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveDeoptimizedStackFrameOp.java	Mon Mar 02 19:11:22 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,6 +35,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLeaveUnpackFramesStackFrameOp.java	Mon Mar 02 19:11:22 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
@@ -37,6 +37,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;
@@ -44,6 +45,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPatchReturnAddressOp.java	Mon Mar 02 19:11:22 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
@@ -38,10 +38,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotPushInterpreterFrameOp.java	Mon Mar 02 19:11:22 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
@@ -38,6 +38,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;
@@ -45,6 +46,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/SPARCHotSpotRegisterConfig.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotRegisterConfig.java	Mon Mar 02 19:11:22 2015 +0100
@@ -92,7 +92,8 @@
     private final Register[] fpuParameterRegisters = {f0, f1, f2, f3, f4, f5, f6, f7};
     // @formatter:off
     private final Register[] callerSaveRegisters =
-                   {g1, g3, g4, g5, o0, o1, o2, o3, o4, o5, o7,
+                   {g1, g2, g3, g4, g5, g6, g7,
+                    o0, o1, o2, o3, o4, o5, o7,
                     f0,  f1,  f2,  f3,  f4,  f5,  f6,  f7,
                     f8,  f9,  f10, f11, f12, f13, f14, f15,
                     f16, f17, f18, f19, f20, f21, f22, f23,
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotReturnOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotSafepointOp.java	Mon Mar 02 19:11:22 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,6 +42,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;
@@ -49,9 +50,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotUnwindOp.java	Mon Mar 02 19:11:22 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("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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectStaticCallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotspotDirectVirtualCallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCIndirectCallOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCPrefetchOp.java	Mon Mar 02 19:11:22 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,15 +26,18 @@
 import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
 
 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -184,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());
@@ -195,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());
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/ClassSubstitutionsTests.java	Mon Mar 02 19:11:22 2015 +0100
@@ -181,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/DataPatchTest.java	Mon Mar 02 19:11:22 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/HotSpotMonitorValueTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotMonitorValueTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -35,7 +35,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.test.*;
-import com.oracle.graal.hotspot.meta.*;
 
 public class HotSpotMonitorValueTest extends GraalCompilerTest {
 
@@ -53,14 +52,14 @@
                         assertNull(caller.caller());
                         assertDeepEquals(2, frame.numLocks);
                         assertDeepEquals(2, caller.numLocks);
-                        HotSpotMonitorValue lock1 = (HotSpotMonitorValue) frame.getLockValue(0);
-                        HotSpotMonitorValue lock2 = (HotSpotMonitorValue) frame.getLockValue(1);
-                        HotSpotMonitorValue lock3 = (HotSpotMonitorValue) caller.getLockValue(0);
-                        HotSpotMonitorValue lock4 = (HotSpotMonitorValue) caller.getLockValue(1);
+                        StackLockValue lock1 = (StackLockValue) frame.getLockValue(0);
+                        StackLockValue lock2 = (StackLockValue) frame.getLockValue(1);
+                        StackLockValue lock3 = (StackLockValue) caller.getLockValue(0);
+                        StackLockValue lock4 = (StackLockValue) caller.getLockValue(1);
 
-                        List<HotSpotMonitorValue> locks = Arrays.asList(lock1, lock2, lock3, lock4);
-                        for (HotSpotMonitorValue lock : locks) {
-                            for (HotSpotMonitorValue other : locks) {
+                        List<StackLockValue> locks = Arrays.asList(lock1, lock2, lock3, lock4);
+                        for (StackLockValue lock : locks) {
+                            for (StackLockValue other : locks) {
                                 if (other != lock) {
                                     // Every lock must have a different stack slot
                                     assertThat(lock.getSlot(), not(other.getSlot()));
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeClassSubstitutionsTest.java	Mon Mar 02 18:44:14 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotNodeSubstitutionsTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -40,7 +40,7 @@
         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/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon Mar 02 19:11:22 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
@@ -164,7 +172,7 @@
                 }
             }
         };
-        for (AbstractBlock<?> block : lir.codeEmittingOrder()) {
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
             for (LIRInstruction op : lir.getLIRforBlock(block)) {
                 if (op instanceof LabelOp) {
                     // Don't consider this as a definition
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCompiledNmethod.java	Mon Mar 02 19:11:22 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.
  */
@@ -36,6 +38,12 @@
     public final int id;
     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);
     }
@@ -52,4 +60,8 @@
     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/HotSpotDebugInfoBuilder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugInfoBuilder.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.nodes.*;
 
@@ -57,7 +56,7 @@
         JavaValue object = toValue(lock);
         boolean eliminated = object instanceof VirtualObject && state.monitorIdAt(lockIndex) != null;
         assert state.monitorIdAt(lockIndex) == null || state.monitorIdAt(lockIndex).getLockDepth() == lockDepth;
-        return new HotSpotMonitorValue(object, slot, eliminated);
+        return new StackLockValue(object, slot, eliminated);
     }
 
     @Override
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotHostBackend.java	Mon Mar 02 19:11:22 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,8 +73,8 @@
 
         try (InitTimer st = timer("graphBuilderPlugins.initialize")) {
             GraphBuilderPhase phase = (GraphBuilderPhase) providers.getSuites().getDefaultGraphBuilderSuite().findPhase(GraphBuilderPhase.class).previous();
-            GraphBuilderPlugins plugins = phase.getGraphBuilderPlugins();
-            registerGraphBuilderPlugins(providers.getMetaAccess(), plugins);
+            InvocationPlugins plugins = phase.getGraphBuilderConfig().getInvocationPlugins();
+            registerInvocationPlugins(providers, plugins);
         }
 
         try (InitTimer st = timer("foreignCalls.initialize")) {
@@ -101,8 +106,8 @@
         }
     }
 
-    protected void registerGraphBuilderPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        StandardGraphBuilderPlugins.registerPlugins(metaAccess, plugins);
-        HotSpotGraphBuilderPlugins.registerPlugins(metaAccess, plugins);
+    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/HotSpotLIRFrameState.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotLIRFrameState.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,12 +26,11 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 
 /**
- * Extends {@link LIRFrameState} to handle {@link HotSpotMonitorValue}s correctly.
+ * Extends {@link LIRFrameState} to handle {@link StackLockValue}s correctly.
  */
 class HotSpotLIRFrameState extends LIRFrameState {
 
@@ -41,8 +40,8 @@
 
     @Override
     protected Value processValue(LIRInstruction inst, InstructionValueProcedure proc, Value value) {
-        if (value instanceof HotSpotMonitorValue) {
-            HotSpotMonitorValue monitor = (HotSpotMonitorValue) value;
+        if (value instanceof StackLockValue) {
+            StackLockValue monitor = (StackLockValue) value;
             if (monitor.getOwner() instanceof Value) {
                 Value owner = (Value) monitor.getOwner();
                 if (processed(owner)) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Mon Mar 02 19:11:22 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;
@@ -1346,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Mon Mar 02 19:11:22 2015 +0100
@@ -356,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotCodeCacheProvider.java	Mon Mar 02 19:11:22 2015 +0100
@@ -169,14 +169,14 @@
         }
 
         public static String tryDisassemble(String hcfEmbeddedString) {
-// if (processMethod != null) {
-// try {
-// return (String) processMethod.invoke(null, hcfEmbeddedString);
-// } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
-// // If the tool is available, for now let's be noisy when it fails
-// throw new GraalInternalError(e);
-// }
-// }
+            if (processMethod != null) {
+                try {
+                    return (String) processMethod.invoke(null, hcfEmbeddedString);
+                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+                    // If the tool is available, for now let's be noisy when it fails
+                    throw new GraalInternalError(e);
+                }
+            }
             return hcfEmbeddedString;
         }
     }
@@ -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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantPool.java	Mon Mar 02 19:11:22 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);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Mar 02 19:11:22 2015 +0100
@@ -22,28 +22,46 @@
  */
 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.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.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.*;
 
 /**
- * Provider of HotSpot specific {@link GraphBuilderPlugin}s.
+ * Provides HotSpot specific {@link InvocationPlugin}s.
  */
 public class HotSpotGraphBuilderPlugins {
-    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        // Object.class
+    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) {
@@ -60,9 +78,10 @@
                 return true;
             }
         });
+    }
 
-        // Class.class
-        r = new Registration(plugins, metaAccess, Class.class);
+    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()) {
@@ -88,9 +107,10 @@
                 return false;
             }
         });
+    }
 
-        // StableOptionValue.class
-        r = new Registration(plugins, metaAccess, StableOptionValue.class);
+    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()) {
@@ -104,4 +124,130 @@
             }
         });
     }
+
+    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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotHostForeignCallsProvider.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMemoryAccessProviderImpl.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodDataAccessor.java	Mon Mar 02 19:11:22 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/HotSpotMonitorValue.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +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.meta;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-
-/**
- * Represents lock information in the debug information.
- */
-public final class HotSpotMonitorValue extends AbstractValue implements JavaValue {
-
-    private static final long serialVersionUID = 8241681800464483691L;
-
-    private JavaValue owner;
-    private StackSlotValue slot;
-    private final boolean eliminated;
-
-    public HotSpotMonitorValue(JavaValue owner, StackSlotValue slot, boolean eliminated) {
-        super(LIRKind.Illegal);
-        this.owner = owner;
-        this.slot = slot;
-        this.eliminated = eliminated;
-    }
-
-    public JavaValue getOwner() {
-        return owner;
-    }
-
-    public void setOwner(JavaValue newOwner) {
-        this.owner = newOwner;
-    }
-
-    public Value getSlot() {
-        return slot;
-    }
-
-    public boolean isEliminated() {
-        return eliminated;
-    }
-
-    @Override
-    public String toString() {
-        return "monitor[" + owner + (slot != null ? ", " + slot : "") + (eliminated ? ", eliminated" : "") + "]";
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 43;
-        int result = super.hashCode();
-        result = prime * result + (eliminated ? 1231 : 1237);
-        result = prime * result + owner.hashCode();
-        result = prime * result + slot.hashCode();
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof HotSpotMonitorValue) {
-            HotSpotMonitorValue other = (HotSpotMonitorValue) obj;
-            return super.equals(obj) && eliminated == other.eliminated && owner.equals(other.owner) && slot.equals(other.slot);
-        }
-        return false;
-    }
-
-    public void setSlot(StackSlotValue stackSlot) {
-        assert slot == null || (isVirtualStackSlot(slot) && (slot.equals(stackSlot) || isStackSlot(stackSlot))) : String.format("Can not set slot for %s to %s", this, stackSlot);
-        slot = stackSlot;
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstant.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl.java	Mon Mar 02 19:11:22 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());
@@ -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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSignature.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Mon Mar 02 19:11:22 2015 +0100
@@ -22,21 +22,31 @@
  */
 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.*;
 
 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}.
@@ -68,9 +78,9 @@
 
     }
 
-    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime) {
+    public HotSpotSuitesProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, Replacements replacements) {
         this.runtime = runtime;
-        this.defaultGraphBuilderSuite = createGraphBuilderSuite();
+        this.defaultGraphBuilderSuite = createGraphBuilderSuite(metaAccess, constantReflection, replacements);
         this.defaultSuites = new DerivedOptionValue<>(new SuitesSupplier());
         this.defaultLIRSuites = new DerivedOptionValue<>(new LIRSuitesSupplier());
     }
@@ -102,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;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/AllocaNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ArrayRangeWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/BeginLockScopeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CStringNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassCastNode.java	Mon Mar 02 19:11:22 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.*;
@@ -38,8 +39,10 @@
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Mon Mar 02 19:11:22 2015 +0100
@@ -40,8 +40,10 @@
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetComponentTypeNode.java	Mon Mar 02 19:11:22 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,8 +39,10 @@
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetModifiersNode.java	Mon Mar 02 19:11:22 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,9 +37,10 @@
  */
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetSuperclassNode.java	Mon Mar 02 19:11:22 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,8 +39,10 @@
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsArrayNode.java	Mon Mar 02 19:11:22 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
@@ -38,8 +38,10 @@
 @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/ClassIsInterfaceNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsInterfaceNode.java	Mon Mar 02 19:11:22 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
@@ -38,8 +38,10 @@
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassIsPrimitiveNode.java	Mon Mar 02 19:11:22 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
@@ -38,8 +38,10 @@
 @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CompressionNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentJavaThreadNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/CurrentLockNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizationFetchUnrollInfoCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizeCallerNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DeoptimizingStubCall.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DimensionsNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/DirectCompareAndSwapNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EndLockScopeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/EnterUnpackFramesStackFrameNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PostWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1PreWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/G1ReferentFieldReadBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/GetObjectAddressNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotDirectCallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/HotSpotIndirectCallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/JumpToExceptionHandlerInCallerNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveCurrentStackFrameNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveDeoptimizedStackFrameNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LeaveUnpackFramesStackFrameNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/LoadIndexedPointerNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/MonitorCounterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewArrayStubCall.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewInstanceStubCall.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/NewMultiArrayStubCall.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PatchReturnAddressNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PrefetchAllocateNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/PushInterpreterFrameNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SaveAllRegistersNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SerialWriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetAnchorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/SnippetLocationProxyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubForeignCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/StubStartNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/UncommonTrapCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/VMErrorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/WriteBarrier.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CallSiteTargetNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -34,8 +34,10 @@
 @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() {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CardTableAddressNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CardTableAddressNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CardTableShiftNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassGetHubNode.java	Mon Mar 02 19:11:22 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/CompositeValueClassSubstitutions.java	Mon Mar 02 18:44:14 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);
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotNodeClassSubstitutions.java	Mon Mar 02 18:44:14 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	Mon Mar 02 18:44:14 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotReplacementsUtil.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Mon Mar 02 19:11:22 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.*;
 
@@ -63,9 +61,6 @@
         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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HubGetClassNode.java	Mon Mar 02 19:11:22 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;
 
     public HubGetClassNode(@InjectedNodeParameter MetaAccessProvider metaAccess, ValueNode hub) {
-        super(StampFactory.declaredNonNull(metaAccess.lookupJavaType(Class.class)), null);
+        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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/InstanceOfSnippets.java	Mon Mar 02 19:11:22 2015 +0100
@@ -61,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));
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/KlassLayoutHelperNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/KlassLayoutHelperNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java	Mon Mar 02 19:11:22 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/NewObjectSnippets.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon Mar 02 19:11:22 2015 +0100
@@ -251,7 +251,7 @@
 
     /**
      * Computes the size of the memory chunk allocated for an array. This size accounts for the
-     * array header size, boy size and any padding after the last element to satisfy object
+     * array header size, body size and any padding after the last element to satisfy object
      * alignment requirements.
      *
      * @param length the number of elements in the array
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectCloneNode.java	Mon Mar 02 19:11:22 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
@@ -30,6 +30,7 @@
 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;
@@ -39,10 +40,12 @@
 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
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ReflectionGetCallerClassNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/SystemIdentityHashCodeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/ArrayCopyNode.java	Mon Mar 02 19:11:22 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) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/DeoptimizationStub.java	Mon Mar 02 19:11:22 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/UncommonTrapStub.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/UncommonTrapStub.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/word/PointerCastNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Mon Mar 02 19:11:22 2015 +0100
@@ -37,11 +37,12 @@
 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.*;
 
-public abstract class AbstractBytecodeParser<T extends KindProvider, F extends AbstractFrameStateBuilder<T, F>> {
+public abstract class AbstractBytecodeParser {
 
     static class Options {
         // @formatter:off
@@ -62,7 +63,7 @@
      */
     public static final int TRACELEVEL_STATE = 2;
 
-    protected F frameState;
+    protected HIRFrameStateBuilder frameState;
     protected BciBlock currentBlock;
 
     protected final BytecodeStream stream;
@@ -74,22 +75,29 @@
     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;
     }
 
-    public void setCurrentFrameState(F frameState) {
+    public void setCurrentFrameState(HIRFrameStateBuilder frameState) {
         this.frameState = frameState;
     }
 
@@ -106,11 +114,11 @@
     }
 
     public void storeLocal(Kind kind, int index) {
-        T value;
+        ValueNode value;
         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);
         }
@@ -126,13 +134,13 @@
      * @param type the unresolved type of the type check
      * @param object the object value whose type is being checked against {@code type}
      */
-    protected abstract void handleUnresolvedCheckCast(JavaType type, T object);
+    protected abstract void handleUnresolvedCheckCast(JavaType type, ValueNode object);
 
     /**
      * @param type the unresolved type of the type check
      * @param object the object value whose type is being checked against {@code type}
      */
-    protected abstract void handleUnresolvedInstanceOf(JavaType type, T object);
+    protected abstract void handleUnresolvedInstanceOf(JavaType type, ValueNode object);
 
     /**
      * @param type the type being instantiated
@@ -143,26 +151,26 @@
      * @param type the type of the array being instantiated
      * @param length the length of the array
      */
-    protected abstract void handleUnresolvedNewObjectArray(JavaType type, T length);
+    protected abstract void handleUnresolvedNewObjectArray(JavaType type, ValueNode length);
 
     /**
      * @param type the type being instantiated
      * @param dims the dimensions for the multi-array
      */
-    protected abstract void handleUnresolvedNewMultiArray(JavaType type, List<T> dims);
+    protected abstract void handleUnresolvedNewMultiArray(JavaType type, List<ValueNode> dims);
 
     /**
      * @param field the unresolved field
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
-    protected abstract void handleUnresolvedLoadField(JavaField field, T receiver);
+    protected abstract void handleUnresolvedLoadField(JavaField field, ValueNode receiver);
 
     /**
      * @param field the unresolved field
      * @param value the value being stored to the field
      * @param receiver the object containing the field or {@code null} if {@code field} is static
      */
-    protected abstract void handleUnresolvedStoreField(JavaField field, T value, T receiver);
+    protected abstract void handleUnresolvedStoreField(JavaField field, ValueNode value, ValueNode receiver);
 
     /**
      * @param type
@@ -171,7 +179,7 @@
 
     // protected abstract void handleUnresolvedInvoke(JavaMethod javaMethod, InvokeKind invokeKind);
 
-    // protected abstract DispatchBeginNode handleException(T exceptionObject, int bci);
+    // protected abstract DispatchBeginNode handleException(ValueNode exceptionObject, int bci);
 
     private void genLoadConstant(int cpi, int opcode) {
         Object con = lookupConstant(cpi, opcode);
@@ -192,56 +200,41 @@
         }
     }
 
-    protected abstract T genLoadIndexed(T index, T array, Kind kind);
+    protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind);
 
     private void genLoadIndexed(Kind kind) {
         emitExplicitExceptions(frameState.peek(1), frameState.peek(0));
 
-        T index = frameState.ipop();
-        T array = frameState.apop();
+        ValueNode index = frameState.ipop();
+        ValueNode array = frameState.apop();
         frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
     }
 
-    protected abstract T genStoreIndexed(T array, T index, Kind kind, T value);
+    protected abstract ValueNode genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
 
     private void genStoreIndexed(Kind kind) {
         emitExplicitExceptions(frameState.peek(2), frameState.peek(1));
 
-        T value = frameState.pop(kind.getStackKind());
-        T index = frameState.ipop();
-        T array = frameState.apop();
+        ValueNode value = frameState.pop(kind.getStackKind());
+        ValueNode index = frameState.ipop();
+        ValueNode array = frameState.apop();
         append(genStoreIndexed(array, index, kind, value));
     }
 
     private void stackOp(int opcode) {
         switch (opcode) {
-            case POP: {
-                frameState.xpop();
-                break;
-            }
-            case POP2: {
-                frameState.xpop();
-                frameState.xpop();
-                break;
-            }
-            case DUP: {
-                T w = frameState.xpop();
-                frameState.xpush(w);
-                frameState.xpush(w);
-                break;
-            }
             case DUP_X1: {
-                T w1 = frameState.xpop();
-                T w2 = frameState.xpop();
+                ValueNode w1 = frameState.xpop();
+                ValueNode w2 = frameState.xpop();
                 frameState.xpush(w1);
                 frameState.xpush(w2);
                 frameState.xpush(w1);
                 break;
             }
             case DUP_X2: {
-                T w1 = frameState.xpop();
-                T w2 = frameState.xpop();
-                T w3 = frameState.xpop();
+                ValueNode w1 = frameState.xpop();
+                ValueNode w2 = frameState.xpop();
+                ValueNode w3 = frameState.xpop();
                 frameState.xpush(w1);
                 frameState.xpush(w3);
                 frameState.xpush(w2);
@@ -249,8 +242,8 @@
                 break;
             }
             case DUP2: {
-                T w1 = frameState.xpop();
-                T w2 = frameState.xpop();
+                ValueNode w1 = frameState.xpop();
+                ValueNode w2 = frameState.xpop();
                 frameState.xpush(w2);
                 frameState.xpush(w1);
                 frameState.xpush(w2);
@@ -258,9 +251,9 @@
                 break;
             }
             case DUP2_X1: {
-                T w1 = frameState.xpop();
-                T w2 = frameState.xpop();
-                T w3 = frameState.xpop();
+                ValueNode w1 = frameState.xpop();
+                ValueNode w2 = frameState.xpop();
+                ValueNode w3 = frameState.xpop();
                 frameState.xpush(w2);
                 frameState.xpush(w1);
                 frameState.xpush(w3);
@@ -269,10 +262,10 @@
                 break;
             }
             case DUP2_X2: {
-                T w1 = frameState.xpop();
-                T w2 = frameState.xpop();
-                T w3 = frameState.xpop();
-                T w4 = frameState.xpop();
+                ValueNode w1 = frameState.xpop();
+                ValueNode w2 = frameState.xpop();
+                ValueNode w3 = frameState.xpop();
+                ValueNode w4 = frameState.xpop();
                 frameState.xpush(w2);
                 frameState.xpush(w1);
                 frameState.xpush(w4);
@@ -282,8 +275,8 @@
                 break;
             }
             case SWAP: {
-                T w1 = frameState.xpop();
-                T w2 = frameState.xpop();
+                ValueNode w1 = frameState.xpop();
+                ValueNode w2 = frameState.xpop();
                 frameState.xpush(w1);
                 frameState.xpush(w2);
                 break;
@@ -293,27 +286,27 @@
         }
     }
 
-    protected abstract T genIntegerAdd(Kind kind, T x, T y);
+    protected abstract ValueNode genIntegerAdd(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genIntegerSub(Kind kind, T x, T y);
+    protected abstract ValueNode genIntegerSub(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genIntegerMul(Kind kind, T x, T y);
+    protected abstract ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genFloatAdd(Kind kind, T x, T y, boolean isStrictFP);
+    protected abstract ValueNode genFloatAdd(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
 
-    protected abstract T genFloatSub(Kind kind, T x, T y, boolean isStrictFP);
+    protected abstract ValueNode genFloatSub(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
 
-    protected abstract T genFloatMul(Kind kind, T x, T y, boolean isStrictFP);
+    protected abstract ValueNode genFloatMul(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
 
-    protected abstract T genFloatDiv(Kind kind, T x, T y, boolean isStrictFP);
+    protected abstract ValueNode genFloatDiv(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
 
-    protected abstract T genFloatRem(Kind kind, T x, T y, boolean isStrictFP);
+    protected abstract ValueNode genFloatRem(Kind kind, ValueNode x, ValueNode y, boolean isStrictFP);
 
     private void genArithmeticOp(Kind result, int opcode) {
-        T y = frameState.pop(result);
-        T x = frameState.pop(result);
+        ValueNode y = frameState.pop(result);
+        ValueNode x = frameState.pop(result);
         boolean isStrictFP = method.isStrict();
-        T v;
+        ValueNode v;
         switch (opcode) {
             case IADD:
             case LADD:
@@ -353,14 +346,14 @@
         frameState.push(result, append(v));
     }
 
-    protected abstract T genIntegerDiv(Kind kind, T x, T y);
+    protected abstract ValueNode genIntegerDiv(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genIntegerRem(Kind kind, T x, T y);
+    protected abstract ValueNode genIntegerRem(Kind kind, ValueNode x, ValueNode y);
 
     private void genIntegerDivOp(Kind result, int opcode) {
-        T y = frameState.pop(result);
-        T x = frameState.pop(result);
-        T v;
+        ValueNode y = frameState.pop(result);
+        ValueNode x = frameState.pop(result);
+        ValueNode v;
         switch (opcode) {
             case IDIV:
             case LDIV:
@@ -376,22 +369,22 @@
         frameState.push(result, append(v));
     }
 
-    protected abstract T genNegateOp(T x);
+    protected abstract ValueNode genNegateOp(ValueNode x);
 
     private void genNegateOp(Kind kind) {
         frameState.push(kind, append(genNegateOp(frameState.pop(kind))));
     }
 
-    protected abstract T genLeftShift(Kind kind, T x, T y);
+    protected abstract ValueNode genLeftShift(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genRightShift(Kind kind, T x, T y);
+    protected abstract ValueNode genRightShift(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genUnsignedRightShift(Kind kind, T x, T y);
+    protected abstract ValueNode genUnsignedRightShift(Kind kind, ValueNode x, ValueNode y);
 
     private void genShiftOp(Kind kind, int opcode) {
-        T s = frameState.ipop();
-        T x = frameState.pop(kind);
-        T v;
+        ValueNode s = frameState.ipop();
+        ValueNode x = frameState.pop(kind);
+        ValueNode v;
         switch (opcode) {
             case ISHL:
             case LSHL:
@@ -411,16 +404,16 @@
         frameState.push(kind, append(v));
     }
 
-    protected abstract T genAnd(Kind kind, T x, T y);
+    protected abstract ValueNode genAnd(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genOr(Kind kind, T x, T y);
+    protected abstract ValueNode genOr(Kind kind, ValueNode x, ValueNode y);
 
-    protected abstract T genXor(Kind kind, T x, T y);
+    protected abstract ValueNode genXor(Kind kind, ValueNode x, ValueNode y);
 
     private void genLogicOp(Kind kind, int opcode) {
-        T y = frameState.pop(kind);
-        T x = frameState.pop(kind);
-        T v;
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
+        ValueNode v;
         switch (opcode) {
             case IAND:
             case LAND:
@@ -440,29 +433,29 @@
         frameState.push(kind, append(v));
     }
 
-    protected abstract T genNormalizeCompare(T x, T y, boolean isUnorderedLess);
+    protected abstract ValueNode genNormalizeCompare(ValueNode x, ValueNode y, boolean isUnorderedLess);
 
     private void genCompareOp(Kind kind, boolean isUnorderedLess) {
-        T y = frameState.pop(kind);
-        T x = frameState.pop(kind);
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
         frameState.ipush(append(genNormalizeCompare(x, y, isUnorderedLess)));
     }
 
-    protected abstract T genFloatConvert(FloatConvert op, T input);
+    protected abstract ValueNode genFloatConvert(FloatConvert op, ValueNode input);
 
     private void genFloatConvert(FloatConvert op, Kind from, Kind to) {
-        T input = frameState.pop(from.getStackKind());
+        ValueNode input = frameState.pop(from.getStackKind());
         frameState.push(to.getStackKind(), append(genFloatConvert(op, input)));
     }
 
-    protected abstract T genNarrow(T input, int bitCount);
+    protected abstract ValueNode genNarrow(ValueNode input, int bitCount);
 
-    protected abstract T genSignExtend(T input, int bitCount);
+    protected abstract ValueNode genSignExtend(ValueNode input, int bitCount);
 
-    protected abstract T genZeroExtend(T input, int bitCount);
+    protected abstract ValueNode genZeroExtend(ValueNode input, int bitCount);
 
     private void genSignExtend(Kind from, Kind to) {
-        T input = frameState.pop(from.getStackKind());
+        ValueNode input = frameState.pop(from.getStackKind());
         if (from != from.getStackKind()) {
             input = append(genNarrow(input, from.getBitCount()));
         }
@@ -470,7 +463,7 @@
     }
 
     private void genZeroExtend(Kind from, Kind to) {
-        T input = frameState.pop(from.getStackKind());
+        ValueNode input = frameState.pop(from.getStackKind());
         if (from != from.getStackKind()) {
             input = append(genNarrow(input, from.getBitCount()));
         }
@@ -478,46 +471,45 @@
     }
 
     private void genNarrow(Kind from, Kind to) {
-        T input = frameState.pop(from.getStackKind());
+        ValueNode input = frameState.pop(from.getStackKind());
         frameState.push(to.getStackKind(), append(genNarrow(input, to.getBitCount())));
     }
 
     private void genIncrement() {
         int index = getStream().readLocalIndex();
         int delta = getStream().readIncrement();
-        T x = frameState.loadLocal(index);
-        T y = appendConstant(JavaConstant.forInt(delta));
+        ValueNode x = frameState.loadLocal(index);
+        ValueNode y = appendConstant(JavaConstant.forInt(delta));
         frameState.storeLocal(index, append(genIntegerAdd(Kind.Int, x, y)));
     }
 
     protected abstract void genGoto();
 
-    protected abstract T genObjectEquals(T x, T y);
+    protected abstract ValueNode genObjectEquals(ValueNode x, ValueNode y);
 
-    protected abstract T genIntegerEquals(T x, T y);
+    protected abstract ValueNode genIntegerEquals(ValueNode x, ValueNode y);
 
-    protected abstract T genIntegerLessThan(T x, T y);
+    protected abstract ValueNode genIntegerLessThan(ValueNode x, ValueNode y);
 
-    protected abstract T genUnique(T x);
+    protected abstract ValueNode genUnique(ValueNode x);
 
-    protected abstract void genIf(T x, Condition cond, T y);
+    protected abstract void genIf(ValueNode x, Condition cond, ValueNode y);
 
     private void genIfZero(Condition cond) {
-        T y = appendConstant(JavaConstant.INT_0);
-        T x = frameState.ipop();
+        ValueNode y = appendConstant(JavaConstant.INT_0);
+        ValueNode x = frameState.ipop();
         genIf(x, cond, y);
     }
 
     private void genIfNull(Condition cond) {
-        T y = appendConstant(JavaConstant.NULL_POINTER);
-        T x = frameState.apop();
+        ValueNode y = appendConstant(JavaConstant.NULL_POINTER);
+        ValueNode x = frameState.apop();
         genIf(x, cond, y);
     }
 
     private void genIfSame(Kind kind, Condition cond) {
-        T y = frameState.pop(kind);
-        T x = frameState.pop(kind);
-        // assert !x.isDeleted() && !y.isDeleted();
+        ValueNode y = frameState.pop(kind);
+        ValueNode x = frameState.pop(kind);
         genIf(x, cond, y);
     }
 
@@ -564,48 +556,47 @@
     }
 
     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());
         }
     }
 
-    protected abstract T createCheckCast(ResolvedJavaType type, T object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck);
+    protected abstract ValueNode createCheckCast(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck, boolean forStoreCheck);
 
     private void genCheckCast() {
         int cpi = getStream().readCPI();
         JavaType type = lookupType(cpi, CHECKCAST);
-        T object = frameState.apop();
+        ValueNode object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
             JavaTypeProfile profileForTypeCheck = getProfileForTypeCheck((ResolvedJavaType) type);
-            T checkCastNode = append(createCheckCast((ResolvedJavaType) type, object, profileForTypeCheck, false));
+            ValueNode checkCastNode = append(createCheckCast((ResolvedJavaType) type, object, profileForTypeCheck, false));
             frameState.apush(checkCastNode);
         } else {
             handleUnresolvedCheckCast(type, object);
         }
     }
 
-    protected abstract T createInstanceOf(ResolvedJavaType type, T object, JavaTypeProfile profileForTypeCheck);
+    protected abstract ValueNode createInstanceOf(ResolvedJavaType type, ValueNode object, JavaTypeProfile profileForTypeCheck);
 
-    protected abstract T genConditional(T x);
+    protected abstract ValueNode genConditional(ValueNode x);
 
     private void genInstanceOf() {
         int cpi = getStream().readCPI();
         JavaType type = lookupType(cpi, INSTANCEOF);
-        T object = frameState.apop();
+        ValueNode object = frameState.apop();
         if (type instanceof ResolvedJavaType) {
             ResolvedJavaType resolvedType = (ResolvedJavaType) type;
-            T instanceOfNode = createInstanceOf((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType));
+            ValueNode instanceOfNode = createInstanceOf((ResolvedJavaType) type, object, getProfileForTypeCheck(resolvedType));
             frameState.ipush(append(genConditional(genUnique(instanceOfNode))));
         } else {
             handleUnresolvedInstanceOf(type, object);
         }
     }
 
-    protected abstract T createNewInstance(ResolvedJavaType type, boolean fillContents);
+    protected abstract ValueNode createNewInstance(ResolvedJavaType type, boolean fillContents);
 
-    @SuppressWarnings("unchecked")
     void genNewInstance(int cpi) {
         JavaType type = lookupType(cpi, NEW);
         if (type instanceof ResolvedJavaType && ((ResolvedJavaType) type).isInitialized()) {
@@ -613,7 +604,7 @@
             if (skippedExceptionTypes != null) {
                 for (ResolvedJavaType exceptionType : skippedExceptionTypes) {
                     if (exceptionType.isAssignableFrom((ResolvedJavaType) type)) {
-                        append((T) new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
+                        append(new DeoptimizeNode(DeoptimizationAction.None, TransferToInterpreter));
                         return;
                     }
                 }
@@ -664,7 +655,7 @@
 
     private void genNewObjectArray(int cpi) {
         JavaType type = lookupType(cpi, ANEWARRAY);
-        T length = frameState.ipop();
+        ValueNode length = frameState.ipop();
         if (type instanceof ResolvedJavaType) {
             frameState.apush(append(createNewArray((ResolvedJavaType) type, length, true)));
         } else {
@@ -673,12 +664,12 @@
 
     }
 
-    protected abstract T createNewArray(ResolvedJavaType elementType, T length, boolean fillContents);
+    protected abstract ValueNode createNewArray(ResolvedJavaType elementType, ValueNode length, boolean fillContents);
 
     private void genNewMultiArray(int cpi) {
         JavaType type = lookupType(cpi, MULTIANEWARRAY);
         int rank = getStream().readUByte(bci() + 3);
-        List<T> dims = new ArrayList<>(Collections.nCopies(rank, null));
+        List<ValueNode> dims = new ArrayList<>(Collections.nCopies(rank, null));
         for (int i = rank - 1; i >= 0; i--) {
             dims.set(i, frameState.ipop());
         }
@@ -689,18 +680,18 @@
         }
     }
 
-    protected abstract T createNewMultiArray(ResolvedJavaType type, List<T> dims);
+    protected abstract ValueNode createNewMultiArray(ResolvedJavaType type, List<ValueNode> dims);
 
-    protected abstract T genLoadField(T receiver, ResolvedJavaField field);
+    protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field);
 
     private void genGetField(JavaField field) {
         emitExplicitExceptions(frameState.peek(0), null);
 
         Kind kind = field.getKind();
-        T receiver = frameState.apop();
+        ValueNode receiver = frameState.apop();
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
-            GraphBuilderPlugins.LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
-            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, (ValueNode) receiver, (ResolvedJavaField) field)) {
+            LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getLoadFieldPlugin();
+            if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
                 appendOptimizedLoadField(kind, genLoadField(receiver, (ResolvedJavaField) field));
             }
         } else {
@@ -708,36 +699,36 @@
         }
     }
 
-    protected abstract void emitNullCheck(T receiver);
+    protected abstract void emitNullCheck(ValueNode receiver);
 
-    protected abstract void emitBoundsCheck(T index, T length);
+    protected abstract void emitBoundsCheck(ValueNode index, ValueNode length);
 
     private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions");
 
-    protected abstract T genArrayLength(T x);
+    protected abstract ValueNode genArrayLength(ValueNode x);
 
-    protected void emitExplicitExceptions(T receiver, T outOfBoundsIndex) {
+    protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) {
         assert receiver != null;
-        if (graphBuilderConfig.omitAllExceptionEdges() ||
+        if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null ||
                         (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
             return;
         }
 
         emitNullCheck(receiver);
         if (outOfBoundsIndex != null) {
-            T length = append(genArrayLength(receiver));
+            ValueNode length = append(genArrayLength(receiver));
             emitBoundsCheck(outOfBoundsIndex, length);
         }
         EXPLICIT_EXCEPTIONS.increment();
     }
 
-    protected abstract T genStoreField(T receiver, ResolvedJavaField field, T value);
+    protected abstract ValueNode genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value);
 
     private void genPutField(JavaField field) {
         emitExplicitExceptions(frameState.peek(1), null);
 
-        T value = frameState.pop(field.getKind().getStackKind());
-        T receiver = frameState.apop();
+        ValueNode value = frameState.pop(field.getKind().getStackKind());
+        ValueNode receiver = frameState.apop();
         if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
             appendOptimizedStoreField(genStoreField(receiver, (ResolvedJavaField) field, value));
         } else {
@@ -748,7 +739,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));
             }
@@ -758,7 +749,7 @@
     }
 
     private void genPutStatic(JavaField field) {
-        T value = frameState.pop(field.getKind().getStackKind());
+        ValueNode value = frameState.pop(field.getKind().getStackKind());
         if (field instanceof ResolvedJavaField && ((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) {
             appendOptimizedStoreField(genStoreField(null, (ResolvedJavaField) field, value));
         } else {
@@ -766,13 +757,13 @@
         }
     }
 
-    protected void appendOptimizedStoreField(T store) {
+    protected void appendOptimizedStoreField(ValueNode store) {
         append(store);
     }
 
-    protected void appendOptimizedLoadField(Kind kind, T load) {
+    protected void appendOptimizedLoadField(Kind kind, ValueNode load) {
         // append the load to the instruction
-        T optimized = append(load);
+        ValueNode optimized = append(load);
         frameState.push(kind.getStackKind(), optimized);
     }
 
@@ -786,18 +777,18 @@
 
     protected abstract void genInvokeSpecial(JavaMethod target);
 
-    protected abstract void genReturn(T x);
+    protected abstract void genReturn(ValueNode x);
 
-    protected abstract T genMonitorEnter(T x);
+    protected abstract ValueNode genMonitorEnter(ValueNode x);
 
-    protected abstract T genMonitorExit(T x, T returnValue);
+    protected abstract ValueNode genMonitorExit(ValueNode x, ValueNode returnValue);
 
     protected abstract void genJsr(int dest);
 
     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 {
@@ -835,7 +826,7 @@
 
     private void genSwitch(BytecodeSwitch bs) {
         int bci = bci();
-        T value = frameState.ipop();
+        ValueNode value = frameState.ipop();
 
         int nofCases = bs.numberOfCases();
         double[] keyProbabilities = switchProbability(nofCases + 1, bci);
@@ -853,12 +844,13 @@
         int[] keySuccessors = new int[nofCases + 1];
         int deoptSuccessorIndex = -1;
         int nextSuccessorIndex = 0;
+        boolean constantValue = 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);
@@ -879,7 +871,7 @@
 
     }
 
-    protected abstract void genIntegerSwitch(T value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors);
+    protected abstract void genIntegerSwitch(ValueNode value, ArrayList<BciBlock> actualSuccessors, int[] keys, double[] keyProbabilities, int[] keySuccessors);
 
     private static class SuccessorInfo {
 
@@ -892,15 +884,19 @@
         }
     }
 
-    protected abstract T appendConstant(JavaConstant constant);
+    protected abstract ValueNode appendConstant(JavaConstant constant);
 
-    protected abstract T append(T v);
+    protected abstract ValueNode append(ValueNode v);
 
     protected boolean isNeverExecutedCode(double probability) {
         return probability == 0 && optimisticOpts.removeNeverExecutedCode();
     }
 
     protected double branchProbability() {
+        if (profilingInfo == null) {
+            return 0.5;
+        }
+        assert assertAtIfBytecode();
         double probability = profilingInfo.getBranchTakenProbability(bci());
         if (probability < 0) {
             assert probability == -1 : "invalid probability";
@@ -918,6 +914,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) {
@@ -1013,9 +1034,9 @@
         case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
         case CASTORE        : genStoreIndexed(Kind.Char  ); break;
         case SASTORE        : genStoreIndexed(Kind.Short ); break;
-        case POP            : // fall through
-        case POP2           : // fall through
-        case DUP            : // fall through
+        case POP            : frameState.xpop(); break;
+        case POP2           : frameState.xpop(); frameState.xpop(); break;
+        case DUP            : frameState.xpush(frameState.xpeek()); break;
         case DUP_X1         : // fall through
         case DUP_X2         : // fall through
         case DUP2           : // fall through
@@ -1144,14 +1165,15 @@
         return method;
     }
 
-    public F getFrameState() {
+    public HIRFrameStateBuilder getFrameState() {
         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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractFrameStateBuilder.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java	Mon Mar 02 19:11:22 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,8 +32,6 @@
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.compiler.common.*;
 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
@@ -84,11 +82,7 @@
         public int loopId;
         public int loopEnd;
         protected List<BciBlock> successors;
-
-        private FixedWithNextNode firstInstruction;
-        private AbstractFrameStateBuilder<?, ?> entryState;
-        private FixedWithNextNode[] firstInstructionArray;
-        private AbstractFrameStateBuilder<?, ?>[] entryStateArray;
+        private int predecessorCount;
 
         private boolean visited;
         private boolean active;
@@ -127,6 +121,10 @@
             return id;
         }
 
+        public int getPredecessorCount() {
+            return this.predecessorCount;
+        }
+
         public int numNormalSuccessors() {
             if (exceptionDispatchBlock() != null) {
                 return successors.size() - 1;
@@ -245,7 +243,7 @@
             return jsrData;
         }
 
-        public void setEndsWithRet() {
+        void setEndsWithRet() {
             getOrCreateJSRData().endsWithRet = true;
         }
 
@@ -265,7 +263,7 @@
             }
         }
 
-        public void setRetSuccessor(BciBlock bciBlock) {
+        void setRetSuccessor(BciBlock bciBlock) {
             this.getOrCreateJSRData().retSuccessor = bciBlock;
         }
 
@@ -308,78 +306,18 @@
             }
         }
 
-        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 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;
-            }
-        }
-
-        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 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 int getSuccessorCount() {
             return successors.size();
         }
@@ -388,9 +326,21 @@
             return successors;
         }
 
-        public void setId(int i) {
+        void setId(int i) {
             this.id = i;
         }
+
+        public void addSuccessor(BciBlock sux) {
+            successors.add(sux);
+            sux.predecessorCount++;
+        }
+
+        public void clearSucccessors() {
+            for (BciBlock sux : successors) {
+                sux.predecessorCount--;
+            }
+            successors.clear();
+        }
     }
 
     public static class ExceptionDispatchBlock extends BciBlock {
@@ -407,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");
         }
     }
 
@@ -493,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)
@@ -511,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;
             }
@@ -527,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;
                 }
@@ -555,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:
@@ -582,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: {
@@ -599,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;
                 }
@@ -625,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);
                     }
                 }
             }
@@ -637,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();
@@ -653,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;
@@ -669,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++) {
@@ -677,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());
@@ -738,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--) {
@@ -766,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);
                 }
@@ -780,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
@@ -800,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]);
@@ -812,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) {
@@ -830,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;
     }
 
@@ -857,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(" :");
@@ -993,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) {
@@ -1007,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;
@@ -1022,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)"));
         }
@@ -1264,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +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);
-    }
-
-    public DefaultGraphBuilderPlugins copy() {
-        DefaultGraphBuilderPlugins result = new DefaultGraphBuilderPlugins();
-        result.plugins.putAll(plugins);
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        return plugins.keySet().stream().map(m -> m.format("%H.%n(%p)")).collect(Collectors.joining(", "));
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraalDirectivePlugins.java	Mon Mar 02 18:44:14 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderConfiguration.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderContext.java	Mon Mar 02 19:11:22 2015 +0100
@@ -27,6 +27,7 @@
 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.*;
 
 /**
@@ -56,6 +57,13 @@
 
     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)
      */
@@ -66,4 +74,8 @@
         }
         return nonNullValue;
     }
+
+    GuardingNode getCurrentBlockGuard();
+
+    BailoutException bailout(String string);
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,6 +26,9 @@
 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.*;
 
@@ -38,16 +41,17 @@
 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.*;
@@ -65,30 +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(), null, 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,7 +92,6 @@
         private ResolvedJavaMethod rootMethod;
 
         private final GraphBuilderConfiguration graphBuilderConfig;
-        private final GraphBuilderPlugins graphBuilderPlugins;
         private final OptimisticOptimizations optimisticOpts;
         private final StampProvider stampProvider;
         private final ConstantReflectionProvider constantReflection;
@@ -112,12 +105,11 @@
         }
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, GraphBuilderPlugins graphBuilderPlugins, OptimisticOptimizations optimisticOpts) {
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
-            this.graphBuilderPlugins = graphBuilderPlugins;
             this.constantReflection = constantReflection;
             this.snippetReflectionProvider = snippetReflectionProvider;
             assert metaAccess != null;
@@ -125,7 +117,7 @@
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
                         OptimisticOptimizations optimisticOpts) {
-            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, null, optimisticOpts);
+            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts);
         }
 
         @Override
@@ -135,22 +127,33 @@
             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)) {
+                // Remove dead parameters.
+                for (ParameterNode param : currentGraph.getNodes(ParameterNode.TYPE)) {
                     if (param.hasNoUsages()) {
                         assert param.inputs().isEmpty();
                         param.safeDelete();
                     }
                 }
+
+                // Remove redundant begin nodes.
+                for (BeginNode beginNode : currentGraph.getNodes(BeginNode.TYPE)) {
+                    Node predecessor = beginNode.predecessor();
+                    if (predecessor instanceof ControlSplitNode) {
+                        // The begin node is necessary.
+                    } else {
+                        GraphUtil.unlinkFixedNode(beginNode);
+                        beginNode.safeDelete();
+                    }
+                }
             } finally {
                 filter.remove();
             }
@@ -176,13 +179,13 @@
 
         private static class ExplodedLoopContext {
             private BciBlock header;
-            private int targetPeelIteration;
+            private int[] targetPeelIteration;
             private int peelIteration;
         }
 
-        public class BytecodeParser extends AbstractBytecodeParser<ValueNode, HIRFrameStateBuilder> implements GraphBuilderContext {
+        public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext {
 
-            private BciBlock[] loopHeaders;
+            private BciBlockMapping blockMap;
             private LocalLiveness liveness;
             protected final int entryBCI;
             private int currentDepth;
@@ -192,8 +195,6 @@
             private int currentLineNumber;
 
             private ValueNode methodSynchronizedObject;
-            private ExceptionDispatchBlock unwindBlock;
-            private BciBlock returnBlock;
 
             private ValueNode returnValue;
             private FixedWithNextNode beforeReturnNode;
@@ -202,11 +203,25 @@
 
             private FixedWithNextNode lastInstr;                 // the last instruction added
             private final boolean explodeLoops;
+            private final boolean mergeExplosions;
+            private final Map<HIRFrameStateBuilder, Integer> mergeExplosionsMap;
             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()) {
@@ -217,8 +232,17 @@
                 LoopExplosionPlugin loopExplosionPlugin = graphBuilderConfig.getLoopExplosionPlugin();
                 if (loopExplosionPlugin != null) {
                     explodeLoops = loopExplosionPlugin.shouldExplodeLoops(method);
+                    if (explodeLoops) {
+                        mergeExplosions = loopExplosionPlugin.shouldMergeExplosions(method);
+                        mergeExplosionsMap = new HashMap<>();
+                    } else {
+                        mergeExplosions = false;
+                        mergeExplosionsMap = null;
+                    }
                 } else {
                     explodeLoops = false;
+                    mergeExplosions = false;
+                    mergeExplosionsMap = null;
                 }
             }
 
@@ -240,7 +264,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,21 +272,33 @@
                 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));
+                            startNode.setStateAfter(createFrameState(BytecodeFrame.BEFORE_BCI));
                         } else {
-                            frameState.clearNonLiveLocals(blockMap.startBlock, liveness, true);
+                            frameState.clearNonLiveLocals(startBlock, liveness, true);
                             assert bci() == 0;
-                            startNode.setStateAfter(frameState.create(bci()));
+                            startNode.setStateAfter(createFrameState(bci()));
                         }
                     }
 
@@ -270,21 +306,21 @@
                         // 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()));
+                        monitorEnter.setStateAfter(createFrameState(bci()));
                     }
 
                     if (graphBuilderConfig.insertNonSafepointDebugInfo()) {
                         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,15 +329,180 @@
                         BciBlock block = blocks[index];
                         index = iterateBlock(blocks, block);
                     }
-                    processBlock(this, returnBlock);
-                    processBlock(this, unwindBlock);
 
-                    if (Debug.isDumpEnabled()) {
+                    if (this.mergeExplosions) {
+                        Debug.dump(currentGraph, "Before loop detection");
+                        detectLoops(startInstruction);
+                    }
+
+                    if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue() && this.beforeReturnNode != startInstruction) {
                         Debug.dump(currentGraph, "Bytecodes parsed: " + method.getDeclaringClass().getUnqualifiedName() + "." + method.getName());
                     }
                 }
             }
 
+            private void detectLoops(FixedNode startInstruction) {
+                NodeBitMap visited = currentGraph.createNodeBitMap();
+                NodeBitMap active = currentGraph.createNodeBitMap();
+                Stack<Node> stack = new Stack<>();
+                stack.add(startInstruction);
+                visited.mark(startInstruction);
+                while (!stack.isEmpty()) {
+                    Node next = stack.peek();
+                    assert next.isDeleted() || visited.isMarked(next);
+                    if (next.isDeleted() || active.isMarked(next)) {
+                        stack.pop();
+                        if (!next.isDeleted()) {
+                            active.clear(next);
+                        }
+                    } else {
+                        active.mark(next);
+                        for (Node n : next.cfgSuccessors()) {
+                            if (active.contains(n)) {
+                                // Detected cycle.
+                                assert n instanceof MergeNode;
+                                assert next instanceof EndNode;
+                                MergeNode merge = (MergeNode) n;
+                                EndNode endNode = (EndNode) next;
+                                merge.removeEnd(endNode);
+                                FixedNode afterMerge = merge.next();
+                                if (!(afterMerge instanceof EndNode) || !(((EndNode) afterMerge).merge() instanceof LoopBeginNode)) {
+                                    merge.setNext(null);
+                                    LoopBeginNode newLoopBegin = this.appendLoopBegin(merge);
+                                    newLoopBegin.setNext(afterMerge);
+                                }
+                                LoopBeginNode loopBegin = (LoopBeginNode) ((EndNode) merge.next()).merge();
+                                LoopEndNode loopEnd = currentGraph.add(new LoopEndNode(loopBegin));
+                                endNode.replaceAndDelete(loopEnd);
+                            } else if (visited.contains(n)) {
+                                // Normal merge into a branch we are already exploring.
+                            } else {
+                                visited.mark(n);
+                                stack.push(n);
+                            }
+                        }
+                    }
+                }
+
+                Debug.dump(currentGraph, "After loops detected");
+                insertLoopEnds(startInstruction);
+            }
+
+            private void insertLoopEnds(FixedNode startInstruction) {
+                NodeBitMap visited = currentGraph.createNodeBitMap();
+                Stack<Node> stack = new Stack<>();
+                stack.add(startInstruction);
+                visited.mark(startInstruction);
+                List<LoopBeginNode> loopBegins = new ArrayList<>();
+                while (!stack.isEmpty()) {
+                    Node next = stack.pop();
+                    assert visited.isMarked(next);
+                    if (next instanceof LoopBeginNode) {
+                        loopBegins.add((LoopBeginNode) next);
+                    }
+                    for (Node n : next.cfgSuccessors()) {
+                        if (visited.contains(n)) {
+                            // Nothing to do.
+                        } else {
+                            visited.mark(n);
+                            stack.push(n);
+                        }
+                    }
+                }
+
+                IdentityHashMap<LoopBeginNode, List<LoopBeginNode>> innerLoopsMap = new IdentityHashMap<>();
+                for (int i = loopBegins.size() - 1; i >= 0; --i) {
+                    LoopBeginNode loopBegin = loopBegins.get(i);
+                    insertLoopExits(loopBegin, innerLoopsMap);
+                    if (GraalOptions.DumpDuringGraphBuilding.getValue()) {
+                        Debug.dump(currentGraph, "After building loop exits for %s.", loopBegin);
+                    }
+                }
+
+                // Remove degenerated merges with only one predecessor.
+                for (LoopBeginNode loopBegin : loopBegins) {
+                    Node pred = loopBegin.forwardEnd().predecessor();
+                    if (pred instanceof MergeNode) {
+                        MergeNode.removeMergeIfDegenerated((MergeNode) pred);
+                    }
+                }
+            }
+
+            private void insertLoopExits(LoopBeginNode loopBegin, IdentityHashMap<LoopBeginNode, List<LoopBeginNode>> innerLoopsMap) {
+                NodeBitMap visited = currentGraph.createNodeBitMap();
+                Stack<Node> stack = new Stack<>();
+                for (LoopEndNode loopEnd : loopBegin.loopEnds()) {
+                    stack.push(loopEnd);
+                    visited.mark(loopEnd);
+                }
+
+                List<ControlSplitNode> controlSplits = new ArrayList<>();
+                List<LoopBeginNode> innerLoopBegins = new ArrayList<>();
+
+                while (!stack.isEmpty()) {
+                    Node current = stack.pop();
+                    if (current == loopBegin) {
+                        continue;
+                    }
+                    for (Node pred : current.cfgPredecessors()) {
+                        if (!visited.isMarked(pred)) {
+                            visited.mark(pred);
+                            if (pred instanceof LoopExitNode) {
+                                // Inner loop
+                                LoopExitNode loopExitNode = (LoopExitNode) pred;
+                                LoopBeginNode innerLoopBegin = loopExitNode.loopBegin();
+                                if (!visited.isMarked(innerLoopBegin)) {
+                                    stack.push(innerLoopBegin);
+                                    visited.mark(innerLoopBegin);
+                                    innerLoopBegins.add(innerLoopBegin);
+                                }
+                            } else {
+                                if (pred instanceof ControlSplitNode) {
+                                    ControlSplitNode controlSplitNode = (ControlSplitNode) pred;
+                                    controlSplits.add(controlSplitNode);
+                                }
+                                stack.push(pred);
+                            }
+                        }
+                    }
+                }
+
+                for (ControlSplitNode controlSplit : controlSplits) {
+                    for (Node succ : controlSplit.cfgSuccessors()) {
+                        if (!visited.isMarked(succ)) {
+                            LoopExitNode loopExit = currentGraph.add(new LoopExitNode(loopBegin));
+                            FixedNode next = ((FixedWithNextNode) succ).next();
+                            next.replaceAtPredecessor(loopExit);
+                            loopExit.setNext(next);
+                        }
+                    }
+                }
+
+                for (LoopBeginNode inner : innerLoopBegins) {
+                    addLoopExits(loopBegin, inner, innerLoopsMap, visited);
+                    if (GraalOptions.DumpDuringGraphBuilding.getValue()) {
+                        Debug.dump(currentGraph, "After adding loop exits for %s.", inner);
+                    }
+                }
+
+                innerLoopsMap.put(loopBegin, innerLoopBegins);
+            }
+
+            private void addLoopExits(LoopBeginNode loopBegin, LoopBeginNode inner, IdentityHashMap<LoopBeginNode, List<LoopBeginNode>> innerLoopsMap, NodeBitMap visited) {
+                for (LoopExitNode exit : inner.loopExits()) {
+                    if (!visited.isMarked(exit)) {
+                        LoopExitNode newLoopExit = currentGraph.add(new LoopExitNode(loopBegin));
+                        FixedNode next = exit.next();
+                        next.replaceAtPredecessor(newLoopExit);
+                        newLoopExit.setNext(next);
+                    }
+                }
+
+                for (LoopBeginNode innerInner : innerLoopsMap.get(inner)) {
+                    addLoopExits(loopBegin, innerInner, innerLoopsMap, visited);
+                }
+            }
+
             private int iterateBlock(BciBlock[] blocks, BciBlock block) {
                 if (block.isLoopHeader && this.explodeLoops) {
                     return iterateExplodedLoopHeader(blocks, block);
@@ -319,52 +520,49 @@
                 ExplodedLoopContext context = new ExplodedLoopContext();
                 context.header = header;
                 context.peelIteration = this.getCurrentDimension();
-                context.targetPeelIteration = -1;
+                if (this.mergeExplosions) {
+                    this.addToMergeCache(getEntryState(context.header, context.peelIteration), context.peelIteration);
+                }
                 explodeLoopsContext.push(context);
-                Debug.dump(currentGraph, "before loop explosion " + context.peelIteration);
+                if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) {
+                    Debug.dump(currentGraph, "before loop explosion dimension " + context.peelIteration);
+                }
 
+                peelIteration(blocks, header, context);
+                explodeLoopsContext.pop();
+                return header.loopEnd + 1;
+            }
+
+            private void addToMergeCache(HIRFrameStateBuilder key, int dimension) {
+                mergeExplosionsMap.put(key, dimension);
+            }
+
+            private void peelIteration(BciBlock[] blocks, BciBlock header, ExplodedLoopContext context) {
                 while (true) {
-
                     processBlock(this, header);
                     for (int j = header.getId() + 1; j <= header.loopEnd; ++j) {
                         BciBlock block = blocks[j];
                         iterateBlock(blocks, block);
                     }
 
-                    if (context.targetPeelIteration != -1) {
+                    int[] targets = context.targetPeelIteration;
+                    if (targets != null) {
                         // We were reaching the backedge during explosion. Explode further.
-                        Debug.dump(currentGraph, "Before loop explosion " + context.targetPeelIteration);
-                        context.peelIteration = context.targetPeelIteration;
-                        context.targetPeelIteration = -1;
+                        for (int i = 0; i < targets.length; ++i) {
+                            context.peelIteration = targets[i];
+                            context.targetPeelIteration = null;
+                            if (Debug.isDumpEnabled() && DumpDuringGraphBuilding.getValue()) {
+                                Debug.dump(currentGraph, "next loop explosion iteration " + context.peelIteration);
+                            }
+                            if (i < targets.length - 1) {
+                                peelIteration(blocks, header, context);
+                            }
+                        }
                     } else {
                         // We did not reach the backedge. Exit.
-                        Debug.dump(currentGraph, "after loop explosion " + context.peelIteration);
                         break;
                     }
                 }
-                explodeLoopsContext.pop();
-                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;
             }
 
             /**
@@ -473,7 +671,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();
                 /*
@@ -482,7 +680,7 @@
                  * unwind immediately.
                  */
                 if (bci != currentBlock.endBci || dispatchBlock == null) {
-                    dispatchBlock = unwindBlock();
+                    dispatchBlock = blockMap.getUnwindBlock();
                 }
 
                 HIRFrameStateBuilder dispatchState = frameState.copy();
@@ -500,6 +698,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);
@@ -528,7 +727,7 @@
 
             @Override
             protected ValueNode genIntegerMul(Kind kind, ValueNode x, ValueNode y) {
-                return new MulNode(x, y);
+                return MulNode.create(x, y);
             }
 
             @Override
@@ -543,12 +742,12 @@
 
             @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
@@ -588,62 +787,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);
             }
 
@@ -652,8 +851,8 @@
                 return (ValueNode) currentGraph.unique((Node & ValueNumberable) x);
             }
 
-            protected ValueNode genIfNode(ValueNode condition, ValueNode falseSuccessor, ValueNode trueSuccessor, double d) {
-                return new IfNode((LogicNode) condition, (FixedNode) falseSuccessor, (FixedNode) trueSuccessor, d);
+            protected ValueNode genIfNode(LogicNode condition, FixedNode falseSuccessor, FixedNode trueSuccessor, double d) {
+                return new IfNode(condition, falseSuccessor, trueSuccessor, d);
             }
 
             @Override
@@ -708,7 +907,7 @@
                 append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01));
                 lastInstr = falseSucc;
 
-                exception.setStateAfter(frameState.create(bci()));
+                exception.setStateAfter(createFrameState(bci()));
                 exception.setNext(handleException(exception, bci()));
             }
 
@@ -719,7 +918,7 @@
                 append(new IfNode(currentGraph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99));
                 lastInstr = trueSucc;
 
-                exception.setStateAfter(frameState.create(bci()));
+                exception.setStateAfter(createFrameState(bci()));
                 exception.setNext(handleException(exception, bci()));
             }
 
@@ -853,48 +1052,35 @@
                 }
                 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)) {
-                        if (GraalOptions.TraceInlineDuringParsing.getValue()) {
-                            for (int i = 0; i < this.currentDepth; ++i) {
-                                TTY.print(' ');
-                            }
-                            TTY.println("Used invocation plugin for " + targetMethod);
-                        }
-                        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)) {
+                if (tryAnnotatedInvocationPlugin(args, targetMethod)) {
                     if (GraalOptions.TraceInlineDuringParsing.getValue()) {
-                        int bci = this.bci();
-                        for (int i = 0; i < this.currentDepth; ++i) {
-                            TTY.print(' ');
-                        }
-                        StackTraceElement stackTraceElement = this.method.asStackTraceElement(bci);
-                        String s = String.format("%s (%s:%d)", method.getName(), stackTraceElement.getFileName(), stackTraceElement.getLineNumber());
-                        TTY.print(s);
-                        TTY.println(" inlining call " + targetMethod.getName());
+                        TTY.println(format("%sUsed annotated invocation plugin for %s", nSpaces(currentDepth), targetMethod));
                     }
-                    parseAndInlineCallee(targetMethod, args);
                     return;
-                } else {
-                    // System.out.println("Could not inline invoke " + targetMethod);
+                }
+
+                if (tryInline(args, targetMethod, invokeKind, returnType)) {
+                    return;
                 }
 
                 MethodCallTargetNode callTarget = currentGraph.add(createMethodCallTarget(invokeKind, targetMethod, args, returnType));
 
                 // 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);
@@ -904,16 +1090,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";
@@ -922,6 +1109,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) {
@@ -934,12 +1126,38 @@
                 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());
+                        lazyFrameState[0] = createFrameState(bci());
                     }
                     return lazyFrameState[0];
                 });
@@ -959,15 +1177,6 @@
                 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()));
                 }
 
@@ -991,23 +1200,34 @@
                 DispatchBeginNode exceptionEdge = handleException(null, bci());
                 InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci()));
                 frameState.pushReturn(resultType, invoke);
-                invoke.setStateAfter(frameState.create(stream.nextBCI()));
+                invoke.setStateAfter(createFrameState(stream.nextBCI()));
                 return invoke;
             }
 
             @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));
                 }
             }
 
@@ -1018,7 +1238,7 @@
 
                 synchronizedEpilogue(BytecodeFrame.AFTER_BCI, x);
                 if (frameState.lockDepth() != 0) {
-                    throw new BailoutException("unbalanced monitors");
+                    throw bailout("unbalanced monitors");
                 }
             }
 
@@ -1035,7 +1255,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;
@@ -1055,7 +1275,7 @@
                 }
                 ConstantNode nextBciNode = getJsrConstant(nextBci);
                 frameState.push(Kind.Int, nextBciNode);
-                appendGoto(createTarget(successor, frameState));
+                appendGoto(successor);
             }
 
             @Override
@@ -1071,7 +1291,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) {
@@ -1083,10 +1303,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));
+                    }
                 }
             }
 
@@ -1146,6 +1379,9 @@
             }
 
             public <T extends FloatingNode> T append(T v) {
+                if (v.graph() != null) {
+                    return v;
+                }
                 T added = currentGraph.unique(v);
                 return added;
             }
@@ -1162,7 +1398,7 @@
                         do {
                             long lMask = 1L << pos;
                             if ((exits & lMask) != 0) {
-                                exitLoops.add(loopHeaders[pos]);
+                                exitLoops.add(blockMap.getLoopHeader(pos));
                                 exits &= ~lMask;
                             }
                             pos++;
@@ -1182,7 +1418,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);
@@ -1191,8 +1427,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, getEntryState(loop, this.getCurrentDimension()));
                             loopExit.setStateAfter(newState.create(bci));
                         }
 
@@ -1203,6 +1439,98 @@
                 return new Target(target, state);
             }
 
+            private HIRFrameStateBuilder getEntryState(BciBlock block, int dimension) {
+                int id = block.id;
+                if (dimension == 0) {
+                    return entryStateArray[id];
+                } else {
+                    return getEntryStateMultiDimension(dimension, id);
+                }
+            }
+
+            private HIRFrameStateBuilder getEntryStateMultiDimension(int dimension, int id) {
+                if (entryStateMatrix != null && dimension - 1 < entryStateMatrix.length) {
+                    HIRFrameStateBuilder[] 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)) {
@@ -1214,124 +1542,156 @@
             }
 
             private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state) {
+                return createTarget(block, state, false, false);
+            }
+
+            private FixedNode createTarget(BciBlock block, HIRFrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
                 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, state);
 
-                            // 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 (canReuseInstruction && (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 ? (canReuseState ? 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 (!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);
+                    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 currentBlock == null || currentBlock.getId() < block.getId() || this.mergeExplosions : "must not be backward branch";
+                assert getFirstInstruction(block, operatingDimension).next() == null || this.mergeExplosions : "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.
+                     * the End Node for the already existing edge.
                      */
-                    AbstractBeginNode placeholder = (AbstractBeginNode) block.getFirstInstruction(operatingDimension);
+                    AbstractBeginNode beginNode = (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();
+                    FixedNode next = beginNode.next();
 
-                    if (placeholder.predecessor() instanceof ControlSplitNode) {
-                        placeholder.setNext(end);
+                    if (beginNode.predecessor() instanceof ControlSplitNode) {
+                        beginNode.setNext(end);
                     } else {
-                        placeholder.replaceAtPredecessor(end);
-                        placeholder.safeDelete();
+                        beginNode.replaceAtPredecessor(end);
+                        beginNode.safeDelete();
                     }
 
                     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);
+                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, HIRFrameStateBuilder state) {
+                if (this.explodeLoops && this.explodeLoopsContext != null && !this.explodeLoopsContext.isEmpty()) {
+                    return findOperatingDimensionWithLoopExplosion(block, state);
+                }
+                return this.getCurrentDimension();
+            }
+
+            private int findOperatingDimensionWithLoopExplosion(BciBlock block, HIRFrameStateBuilder state) {
+                int i;
+                for (i = explodeLoopsContext.size() - 1; i >= 0; --i) {
+                    ExplodedLoopContext context = explodeLoopsContext.elementAt(i);
+                    if (context.header == block) {
+
+                        if (this.mergeExplosions) {
+                            state.clearNonLiveLocals(block, liveness, true);
+                            Integer cachedDimension = mergeExplosionsMap.get(state);
+                            if (cachedDimension != null) {
+                                return cachedDimension;
+                            }
+                        }
+
+                        // We have a hit on our current explosion context loop begin.
+                        if (context.targetPeelIteration == null) {
+                            context.targetPeelIteration = new int[1];
+                        } else {
+                            context.targetPeelIteration = Arrays.copyOf(context.targetPeelIteration, context.targetPeelIteration.length + 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.
+                        if (this.mergeExplosions) {
+                            this.addToMergeCache(state, nextPeelIteration);
+                        }
+                        context.targetPeelIteration[context.targetPeelIteration.length - 1] = 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[context.targetPeelIteration.length - 1];
+                    } 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.
@@ -1355,41 +1715,27 @@
 
             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) {
+                int currentDimension = this.getCurrentDimension();
+                FixedWithNextNode firstInstruction = getFirstInstruction(block, currentDimension);
+                if (firstInstruction == 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, firstInstruction, block.isLoopHeader)) {
 
-                    lastInstr = block.getFirstInstruction(this.getCurrentDimension());
-                    frameState = (HIRFrameStateBuilder) block.getEntryState(this.getCurrentDimension());
+                    lastInstr = firstInstruction;
+                    frameState = getEntryState(block, currentDimension);
                     parser.setCurrentFrameState(frameState);
                     currentBlock = block;
 
-                    if (lastInstr instanceof AbstractMergeNode) {
-                        int bci = block.startBci;
-                        if (block instanceof ExceptionDispatchBlock) {
-                            bci = ((ExceptionDispatchBlock) block).deoptBci;
-                        }
-                        ((AbstractMergeNode) lastInstr).setStateAfter(frameState.create(bci));
+                    if (firstInstruction instanceof AbstractMergeNode) {
+                        setMergeStateAfter(block, firstInstruction);
                     }
 
-                    if (block == returnBlock) {
-                        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) {
-                        if (currentDepth == 0) {
-                            frameState.setRethrowException(false);
-                            createUnwind();
-                        } else {
-                            ValueNode exception = frameState.apop();
-                            this.unwindValue = exception;
-                            this.beforeUnwindNode = this.lastInstr;
-                        }
+                    if (block == blockMap.getReturnBlock()) {
+                        handleReturnBlock();
+                    } else if (block == blockMap.getUnwindBlock()) {
+                        handleUnwindBlock();
                     } else if (block instanceof ExceptionDispatchBlock) {
                         createExceptionDispatch((ExceptionDispatchBlock) block);
                     } else {
@@ -1399,6 +1745,37 @@
                 }
             }
 
+            private void handleUnwindBlock() {
+                if (currentDepth == 0) {
+                    frameState.setRethrowException(false);
+                    createUnwind();
+                } else {
+                    ValueNode exception = frameState.apop();
+                    this.unwindValue = exception;
+                    this.beforeUnwindNode = this.lastInstr;
+                }
+            }
+
+            private void handleReturnBlock() {
+                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;
+            }
+
+            private void setMergeStateAfter(BciBlock block, FixedWithNextNode firstInstruction) {
+                AbstractMergeNode abstractMergeNode = (AbstractMergeNode) firstInstruction;
+                if (abstractMergeNode.stateAfter() == null) {
+                    int bci = block.startBci;
+                    if (block instanceof ExceptionDispatchBlock) {
+                        bci = ((ExceptionDispatchBlock) block).deoptBci;
+                    }
+                    abstractMergeNode.setStateAfter(createFrameState(bci));
+                }
+            }
+
             /**
              * Remove loop header without loop ends. This can happen with degenerated loops like
              * this one:
@@ -1413,7 +1790,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);
@@ -1436,7 +1813,7 @@
                     if (currentReturnValue != null) {
                         frameState.push(currentReturnValue.getKind(), currentReturnValue);
                     }
-                    monitorExit.setStateAfter(frameState.create(bci));
+                    monitorExit.setStateAfter(createFrameState(bci));
                     assert !frameState.rethrowException();
                 }
             }
@@ -1445,7 +1822,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;
                 }
 
@@ -1458,7 +1835,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);
@@ -1469,7 +1846,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();
@@ -1485,9 +1862,10 @@
                 }
             }
 
-            private void appendGoto(FixedNode target) {
-                if (lastInstr != null) {
-                    lastInstr.setNext(target);
+            private void appendGoto(BciBlock successor) {
+                FixedNode targetInstr = createTarget(successor, frameState, true, true);
+                if (lastInstr != null && lastInstr != targetInstr) {
+                    lastInstr.setNext(targetInstr);
                 }
             }
 
@@ -1500,30 +1878,29 @@
                 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());
-                    LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode());
-                    lastInstr.setNext(preLoopEnd);
-                    // Add the single non-loop predecessor of the loop header.
-                    loopBegin.addForwardEnd(preLoopEnd);
+                    controlFlowSplit = true;
+                    LoopBeginNode loopBegin = appendLoopBegin(this.lastInstr);
                     lastInstr = loopBegin;
 
                     // Create phi functions for all local variables and operand stack slots.
                     frameState.insertLoopPhis(liveness, block.loopId, loopBegin);
-                    loopBegin.setStateAfter(frameState.create(block.startBci));
+                    loopBegin.setStateAfter(createFrameState(block.startBci));
 
                     /*
                      * We have seen all forward branches. All subsequent backward branches will
                      * 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);
+                } else if (block.isLoopHeader && explodeLoops && this.mergeExplosions) {
+                    frameState = frameState.copy();
                 }
                 assert lastInstr.next() == null : "instructions already appended at block " + block;
                 Debug.log("  frameState: %s", frameState);
@@ -1547,15 +1924,15 @@
 
                     // 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");
                         }
                         EntryMarkerNode x = append(new EntryMarkerNode());
                         frameState.insertProxies(x);
-                        x.setStateAfter(frameState.create(bci));
+                        x.setStateAfter(createFrameState(bci));
                     }
                     processBytecode(bci, opcode);
 
@@ -1575,7 +1952,7 @@
                         } else {
                             StateSplit stateSplit = (StateSplit) lastInstr;
                             if (stateSplit.stateAfter() == null) {
-                                stateSplit.setStateAfter(frameState.create(bci));
+                                stateSplit.setStateAfter(createFrameState(bci));
                             }
                         }
                     }
@@ -1585,13 +1962,22 @@
                             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;
                         }
                     }
                 }
             }
 
+            private LoopBeginNode appendLoopBegin(FixedWithNextNode fixedWithNext) {
+                EndNode preLoopEnd = currentGraph.add(new EndNode());
+                LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode());
+                fixedWithNext.setNext(preLoopEnd);
+                // Add the single non-loop predecessor of the loop header.
+                loopBegin.addForwardEnd(preLoopEnd);
+                return loopBegin;
+            }
+
             /**
              * A hook for derived classes to modify the last instruction or add other instructions.
              *
@@ -1605,16 +1991,17 @@
 
             private InfopointNode createInfoPointNode(InfopointReason reason) {
                 if (graphBuilderConfig.insertFullDebugInfo()) {
-                    return new FullInfopointNode(reason, frameState.create(bci()));
+                    return new FullInfopointNode(reason, createFrameState(bci()));
                 } else {
                     return new SimpleInfopointNode(reason, new BytecodePosition(null, method, bci()));
                 }
             }
 
-            private void traceState() {
+            private boolean traceState() {
                 if (Debug.isEnabled() && Options.TraceBytecodeParserLevel.getValue() >= TRACELEVEL_STATE && Debug.isLogEnabled()) {
                     traceStateHelper();
                 }
+                return true;
             }
 
             private void traceStateHelper() {
@@ -1631,26 +2018,112 @@
 
             @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));
+                    // The target block is the same independent of the condition.
+                    appendGoto(trueBlock);
                     return;
                 }
 
-                double probability = branchProbability();
+                ValueNode a = x;
+                ValueNode b = y;
 
-                // the mirroring and negation operations get the condition into canonical form
-                boolean mirror = cond.canonicalMirror();
+                // Check whether the condition needs to mirror the operands.
+                if (cond.canonicalMirror()) {
+                    a = y;
+                    b = x;
+                }
+
+                // Create the logic node for the condition.
+                LogicNode condition = createLogicNode(cond, a, b);
+
+                // Check whether the condition needs to negate the result.
                 boolean negate = cond.canonicalNegate();
 
-                ValueNode a = mirror ? y : x;
-                ValueNode b = mirror ? x : y;
+                // Remove a logic negation node and fold it into the negate boolean.
+                if (condition instanceof LogicNegationNode) {
+                    LogicNegationNode logicNegationNode = (LogicNegationNode) condition;
+                    negate = !negate;
+                    condition = logicNegationNode.getValue();
+                }
+
+                if (condition instanceof LogicConstantNode) {
+                    genConstantTargetIf(trueBlock, falseBlock, negate, condition);
+                } else {
+                    if (condition.graph() == null) {
+                        condition = currentGraph.unique(condition);
+                    }
+
+                    // Need to get probability based on current bci.
+                    double probability = branchProbability();
+
+                    if (negate) {
+                        BciBlock tmpBlock = trueBlock;
+                        trueBlock = falseBlock;
+                        falseBlock = tmpBlock;
+                        probability = 1 - probability;
+                    }
+
+                    if (isNeverExecutedCode(probability)) {
+                        append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true));
+                        appendGoto(falseBlock);
+                        return;
+                    } else if (isNeverExecutedCode(1 - probability)) {
+                        append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false));
+                        appendGoto(trueBlock);
+                        return;
+                    }
 
-                ValueNode condition;
+                    int oldBci = stream.currentBCI();
+                    int trueBlockInt = checkPositiveIntConstantPushed(trueBlock);
+                    if (trueBlockInt != -1) {
+                        int falseBlockInt = checkPositiveIntConstantPushed(falseBlock);
+                        if (falseBlockInt != -1) {
+                            if (tryGenConditionalForIf(trueBlock, falseBlock, condition, oldBci, trueBlockInt, falseBlockInt)) {
+                                return;
+                            }
+                        }
+                    }
+
+                    this.controlFlowSplit = true;
+                    FixedNode trueSuccessor = createTarget(trueBlock, frameState, false, false);
+                    FixedNode falseSuccessor = createTarget(falseBlock, frameState, false, true);
+                    ValueNode ifNode = genIfNode(condition, trueSuccessor, falseSuccessor, probability);
+                    append(ifNode);
+                }
+            }
+
+            private boolean tryGenConditionalForIf(BciBlock trueBlock, BciBlock falseBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt) {
+                if (gotoOrFallThroughAfterConstant(trueBlock) && gotoOrFallThroughAfterConstant(falseBlock) && trueBlock.getSuccessor(0) == falseBlock.getSuccessor(0)) {
+                    genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, false);
+                    return true;
+                } else if (this.currentDepth != 0 && returnAfterConstant(trueBlock) && returnAfterConstant(falseBlock)) {
+                    genConditionalForIf(trueBlock, condition, oldBci, trueBlockInt, falseBlockInt, true);
+                    return true;
+                }
+                return false;
+            }
+
+            private void genConditionalForIf(BciBlock trueBlock, LogicNode condition, int oldBci, int trueBlockInt, int falseBlockInt, boolean genReturn) {
+                ConstantNode trueValue = currentGraph.unique(ConstantNode.forInt(trueBlockInt));
+                ConstantNode falseValue = currentGraph.unique(ConstantNode.forInt(falseBlockInt));
+                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);
+                }
+            }
+
+            private LogicNode createLogicNode(Condition cond, ValueNode a, ValueNode b) {
+                LogicNode condition;
                 assert !a.getKind().isNumericFloat();
                 if (cond == Condition.EQ || cond == Condition.NE) {
                     if (a.getKind() == Kind.Object) {
@@ -1662,26 +2135,46 @@
                     assert a.getKind() != Kind.Object && !cond.isUnsigned();
                     condition = genIntegerLessThan(a, b);
                 }
-                condition = genUnique(condition);
+                return condition;
+            }
+
+            private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, boolean negate, LogicNode condition) {
+                LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
+                boolean value = constantLogicNode.getValue();
+                if (negate) {
+                    value = !value;
+                }
+                BciBlock nextBlock = falseBlock;
+                if (value) {
+                    nextBlock = trueBlock;
+                }
+                appendGoto(nextBlock);
+            }
 
-                if (condition instanceof LogicConstantNode) {
-                    LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
-                    boolean value = constantLogicNode.getValue();
-                    if (negate) {
-                        value = !value;
-                    }
-                    BciBlock nextBlock = falseBlock;
-                    if (value) {
-                        nextBlock = trueBlock;
-                    }
-                    appendGoto(createTarget(nextBlock, frameState));
-                } else {
-                    ValueNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
-                    ValueNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
+            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;
+            }
 
-                    ValueNode ifNode = negate ? genIfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : genIfNode(condition, trueSuccessor, falseSuccessor, probability);
-                    append(ifNode);
-                }
+            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() {
@@ -1717,6 +2210,37 @@
                 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 = createFrameState(bci());
+                StackTraceElement[] elements = GraphUtil.approxSourceStackTraceElement(currentFrameState);
+                BailoutException bailout = new BailoutException(string);
+                throw GraphUtil.createBailoutException(string, bailout, elements);
+            }
+
+            private FrameState createFrameState(int bci) {
+                return frameState.create(bci);
+            }
         }
     }
+
+    static String nSpaces(int n) {
+        return n == 0 ? "" : format("%" + n + "s", "");
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPlugin.java	Mon Mar 02 19:11:22 2015 +0100
@@ -22,13 +22,143 @@
  */
 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 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);
+
+        boolean shouldMergeExplosions(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	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,301 +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);
-
-    DefaultGraphBuilderPlugins copy();
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon Mar 02 19:11:22 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
@@ -31,19 +31,35 @@
 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.BciBlockMapping.*;
+import com.oracle.graal.java.GraphBuilderPlugin.ParameterPlugin;
 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.nodes.util.*;
 
-public class HIRFrameStateBuilder extends AbstractFrameStateBuilder<ValueNode, HIRFrameStateBuilder> {
+public final class HIRFrameStateBuilder {
 
     private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
     private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
 
+    protected final ResolvedJavaMethod method;
+    protected int stackSize;
+    protected final ValueNode[] locals;
+    protected final ValueNode[] stack;
+    protected ValueNode[] lockedObjects;
+
+    /**
+     * Specifies if asserting type checks are enabled.
+     */
+    protected final boolean checkTypes;
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    protected boolean rethrowException;
+
     private MonitorIdNode[] monitorIds;
     private final StructuredGraph graph;
     private final Supplier<FrameState> outerFrameStateSupplier;
@@ -54,8 +70,12 @@
      * @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) {
+        this.method = method;
+        this.locals = allocateArray(method.getMaxLocals());
+        this.stack = allocateArray(Math.max(1, method.getMaxStackSize()));
+        this.lockedObjects = allocateArray(0);
+        this.checkTypes = checkTypes;
 
         assert graph != null;
 
@@ -64,26 +84,26 @@
         this.outerFrameStateSupplier = outerFrameStateSupplier;
     }
 
-    public final void initializeFromArgumentsArray(ValueNode[] arguments) {
+    public void initializeFromArgumentsArray(ValueNode[] arguments) {
 
         int javaIndex = 0;
         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++;
         }
     }
 
-    public final void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
+    public void initializeForMethodStart(boolean eagerResolve, ParameterPlugin parameterPlugin) {
 
         int javaIndex = 0;
         int index = 0;
@@ -96,7 +116,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,14 +142,24 @@
             if (param == null) {
                 param = new ParameterNode(index, stamp);
             }
-            storeLocal(javaIndex, graph.unique(param));
+            locals[javaIndex] = graph.unique(param);
             javaIndex += kind.getSlotCount();
             index++;
         }
     }
 
     private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
-        super(other);
+        this.method = other.method;
+        this.stackSize = other.stackSize;
+        this.locals = other.locals.clone();
+        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());
+
         assert other.graph != null;
         graph = other.graph;
         monitorIds = other.monitorIds.length == 0 ? other.monitorIds : other.monitorIds.clone();
@@ -140,8 +170,7 @@
         assert lockedObjects.length == monitorIds.length;
     }
 
-    @Override
-    protected ValueNode[] allocateArray(int length) {
+    private static ValueNode[] allocateArray(int length) {
         return length == 0 ? EMPTY_ARRAY : new ValueNode[length];
     }
 
@@ -172,16 +201,18 @@
         FrameState outerFrameState = null;
         if (outerFrameStateSupplier != null) {
             outerFrameState = outerFrameStateSupplier.get();
+            if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+                FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
+                return newFrameState;
+            }
         }
         return graph.add(new FrameState(outerFrameState, method, bci, locals, stack, stackSize, lockedObjects, Arrays.asList(monitorIds), rethrowException, false));
     }
 
-    @Override
     public HIRFrameStateBuilder copy() {
         return new HIRFrameStateBuilder(this);
     }
 
-    @Override
     public boolean isCompatibleWith(HIRFrameStateBuilder other) {
         assert method.equals(other.method) && graph == other.graph && localsSize() == other.localsSize() : "Can only compare frame states of the same method";
         assert lockedObjects.length == monitorIds.length && other.lockedObjects.length == other.monitorIds.length : "mismatch between lockedObjects and monitorIds";
@@ -211,10 +242,18 @@
         assert isCompatibleWith(other);
 
         for (int i = 0; i < localsSize(); i++) {
-            storeLocal(i, merge(localAt(i), other.localAt(i), block));
+            ValueNode curLocal = localAt(i);
+            ValueNode mergedLocal = merge(curLocal, other.localAt(i), block);
+            if (curLocal != mergedLocal) {
+                storeLocal(i, mergedLocal);
+            }
         }
         for (int i = 0; i < stackSize(); i++) {
-            storeStack(i, merge(stackAt(i), other.stackAt(i), block));
+            ValueNode curStack = stackAt(i);
+            ValueNode mergedStack = merge(curStack, other.stackAt(i), block);
+            if (curStack != mergedStack) {
+                storeStack(i, mergedStack);
+            }
         }
         for (int i = 0; i < lockedObjects.length; i++) {
             lockedObjects[i] = merge(lockedObjects[i], other.lockedObjects[i], block);
@@ -225,7 +264,6 @@
     private ValueNode merge(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
         if (currentValue == null || currentValue.isDeleted()) {
             return null;
-
         } else if (block.isPhiAtMerge(currentValue)) {
             if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
                 propagateDelete((ValuePhiNode) currentValue);
@@ -233,26 +271,27 @@
             }
             ((PhiNode) currentValue).addInput(otherValue);
             return currentValue;
-
         } else if (currentValue != otherValue) {
             assert !(block instanceof LoopBeginNode) : "Phi functions for loop headers are create eagerly for changed locals and all stack slots";
             if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
                 return null;
             }
-
-            ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
-            for (int i = 0; i < block.phiPredecessorCount(); i++) {
-                phi.addInput(currentValue);
-            }
-            phi.addInput(otherValue);
-            assert phi.valueCount() == block.phiPredecessorCount() + 1 : "valueCount=" + phi.valueCount() + " predSize= " + block.phiPredecessorCount();
-            return phi;
-
+            return createValuePhi(currentValue, otherValue, block);
         } else {
             return currentValue;
         }
     }
 
+    private ValuePhiNode createValuePhi(ValueNode currentValue, ValueNode otherValue, AbstractMergeNode block) {
+        ValuePhiNode phi = graph.addWithoutUnique(new ValuePhiNode(currentValue.stamp().unrestricted(), block));
+        for (int i = 0; i < block.phiPredecessorCount(); i++) {
+            phi.addInput(currentValue);
+        }
+        phi.addInput(otherValue);
+        assert phi.valueCount() == block.phiPredecessorCount() + 1;
+        return phi;
+    }
+
     private void propagateDelete(FloatingNode node) {
         assert node instanceof ValuePhiNode || node instanceof ProxyNode;
         if (node.isDeleted()) {
@@ -381,7 +420,6 @@
     /**
      * @return the current lock depth
      */
-    @Override
     public int lockDepth() {
         assert lockedObjects.length == monitorIds.length;
         return lockedObjects.length;
@@ -406,4 +444,490 @@
         }
         return false;
     }
+
+    public void clearNonLiveLocals(BciBlock block, LocalLiveness liveness, boolean liveIn) {
+        /*
+         * (lstadler) if somebody is tempted to remove/disable this clearing code: it's possible to
+         * remove it for normal compilations, but not for OSR compilations - otherwise dead object
+         * slots at the OSR entry aren't cleared. it is also not enough to rely on PiNodes with
+         * Kind.Illegal, because the conflicting branch might not have been parsed.
+         */
+        if (liveness == null) {
+            return;
+        }
+        if (liveIn) {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveIn(block, i)) {
+                    locals[i] = null;
+                }
+            }
+        } else {
+            for (int i = 0; i < locals.length; i++) {
+                if (!liveness.localIsLiveOut(block, i)) {
+                    locals[i] = null;
+                }
+            }
+        }
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public boolean rethrowException() {
+        return rethrowException;
+    }
+
+    /**
+     * @see BytecodeFrame#rethrowException
+     */
+    public void setRethrowException(boolean b) {
+        rethrowException = b;
+    }
+
+    /**
+     * Returns the size of the local variables.
+     *
+     * @return the size of the local variables
+     */
+    public int localsSize() {
+        return locals.length;
+    }
+
+    /**
+     * Gets the current size (height) of the stack.
+     */
+    public int stackSize() {
+        return stackSize;
+    }
+
+    /**
+     * Gets the value in the local variables at the specified index, without any sanity checking.
+     *
+     * @param i the index into the locals
+     * @return the instruction that produced the value for the specified local
+     */
+    public ValueNode localAt(int i) {
+        return locals[i];
+    }
+
+    /**
+     * Get the value on the stack at the specified stack index.
+     *
+     * @param i the index into the stack, with {@code 0} being the bottom of the stack
+     * @return the instruction at the specified position in the stack
+     */
+    public ValueNode stackAt(int i) {
+        return stack[i];
+    }
+
+    /**
+     * Gets the value in the lock at the specified index, without any sanity checking.
+     *
+     * @param i the index into the lock
+     * @return the instruction that produced the value for the specified lock
+     */
+    public ValueNode lockAt(int i) {
+        return lockedObjects[i];
+    }
+
+    public void storeLock(int i, ValueNode lock) {
+        lockedObjects[i] = lock;
+    }
+
+    /**
+     * Loads the local variable at the specified index, checking that the returned value is non-null
+     * and that two-stack values are properly handled.
+     *
+     * @param i the index of the local variable to load
+     * @return the instruction that produced the specified local
+     */
+    public ValueNode loadLocal(int i) {
+        ValueNode x = locals[i];
+        assert assertLoadLocal(i, x);
+        return x;
+    }
+
+    private boolean assertLoadLocal(int i, ValueNode x) {
+        assert x != null : i;
+        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 true;
+    }
+
+    /**
+     * Stores a given local variable at the specified index. If the value occupies two slots, then
+     * the next local variable index is also overwritten.
+     *
+     * @param i the index at which to store
+     * @param x the instruction which produces the value for the local
+     */
+    public void storeLocal(int i, ValueNode x) {
+        assert assertStoreLocal(x);
+        locals[i] = x;
+        if (x != null && x.getKind().needsTwoSlots()) {
+            // if this is a double word, then kill i+1
+            locals[i + 1] = null;
+        }
+        if (x != null && i > 0) {
+            ValueNode p = locals[i - 1];
+            if (p != null && p.getKind().needsTwoSlots()) {
+                // if there was a double word at i - 1, then kill it
+                locals[i - 1] = null;
+            }
+        }
+    }
+
+    private boolean assertStoreLocal(ValueNode x) {
+        assert x == null || !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal) : "unexpected value: " + x;
+        return true;
+    }
+
+    public void storeStack(int i, ValueNode x) {
+        assert assertStoreStack(i, x);
+        stack[i] = x;
+    }
+
+    private boolean assertStoreStack(int i, ValueNode x) {
+        assert x == null || (stack[i] == null || x.getKind() == stack[i].getKind()) : "Method does not handle changes from one-slot to two-slot values or non-alive values";
+        return true;
+    }
+
+    /**
+     * Pushes an instruction onto the stack with the expected type.
+     *
+     * @param kind the type expected for this instruction
+     * @param x the instruction to push onto the stack
+     */
+    public void push(Kind kind, ValueNode x) {
+        assert assertPush(kind, x);
+        xpush(x);
+        if (kind.needsTwoSlots()) {
+            xpush(null);
+        }
+    }
+
+    private boolean assertPush(Kind kind, ValueNode x) {
+        assert !checkTypes || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal);
+        assert x != null && (!checkTypes || x.getKind() == kind);
+        return true;
+    }
+
+    /**
+     * Pushes a value onto the stack without checking the type.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void xpush(ValueNode x) {
+        assert assertXpush(x);
+        stack[stackSize++] = x;
+    }
+
+    private boolean assertXpush(ValueNode x) {
+        assert !checkTypes || (x == null || (x.getKind() != Kind.Void && x.getKind() != Kind.Illegal));
+        return true;
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an int.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void ipush(ValueNode x) {
+        assert assertInt(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a float.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void fpush(ValueNode x) {
+        assert assertFloat(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is an object.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void apush(ValueNode x) {
+        assert assertObject(x);
+        xpush(x);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a long.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void lpush(ValueNode x) {
+        assert assertLong(x);
+        xpush(x);
+        xpush(null);
+    }
+
+    /**
+     * Pushes a value onto the stack and checks that it is a double.
+     *
+     * @param x the instruction to push onto the stack
+     */
+    public void dpush(ValueNode x) {
+        assert assertDouble(x);
+        xpush(x);
+        xpush(null);
+    }
+
+    public void pushReturn(Kind kind, ValueNode x) {
+        if (kind != Kind.Void) {
+            push(kind.getStackKind(), x);
+        }
+    }
+
+    /**
+     * Pops an instruction off the stack with the expected type.
+     *
+     * @param kind the expected type
+     * @return the instruction on the top of the stack
+     */
+    public ValueNode pop(Kind kind) {
+        if (kind.needsTwoSlots()) {
+            xpop();
+        }
+        assert assertPop(kind);
+        return xpop();
+    }
+
+    private boolean assertPop(Kind kind) {
+        assert kind != Kind.Void;
+        ValueNode x = xpeek();
+        assert x != null && (!checkTypes || x.getKind() == kind);
+        return true;
+    }
+
+    /**
+     * Pops a value off of the stack without checking the type.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode xpop() {
+        return stack[--stackSize];
+    }
+
+    public ValueNode xpeek() {
+        return stack[stackSize - 1];
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an int.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode ipop() {
+        assert assertIntPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a float.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode fpop() {
+        assert assertFloatPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is an object.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode apop() {
+        assert assertObjectPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a long.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode lpop() {
+        assert assertHighPeek();
+        xpop();
+        assert assertLongPeek();
+        return xpop();
+    }
+
+    /**
+     * Pops a value off of the stack and checks that it is a double.
+     *
+     * @return x the instruction popped off the stack
+     */
+    public ValueNode dpop() {
+        assert assertHighPeek();
+        xpop();
+        assert assertDoublePeek();
+        return xpop();
+    }
+
+    /**
+     * Pop the specified number of slots off of this stack and return them as an array of
+     * instructions.
+     *
+     * @return an array containing the arguments off of the stack
+     */
+    public ValueNode[] popArguments(int argSize) {
+        ValueNode[] result = allocateArray(argSize);
+        int newStackSize = stackSize;
+        for (int i = argSize - 1; i >= 0; i--) {
+            newStackSize--;
+            if (stack[newStackSize] == null) {
+                /* Two-slot value. */
+                newStackSize--;
+                assert stack[newStackSize].getKind().needsTwoSlots();
+            } else {
+                assert !checkTypes || (stack[newStackSize].getKind().getSlotCount() == 1);
+            }
+            result[i] = stack[newStackSize];
+        }
+        stackSize = newStackSize;
+        return result;
+    }
+
+    /**
+     * Peeks an element from the operand stack.
+     *
+     * @param argumentNumber The number of the argument, relative from the top of the stack (0 =
+     *            top). Long and double arguments only count as one argument, i.e., null-slots are
+     *            ignored.
+     * @return The peeked argument.
+     */
+    public ValueNode peek(int argumentNumber) {
+        int idx = stackSize() - 1;
+        for (int i = 0; i < argumentNumber; i++) {
+            if (stackAt(idx) == null) {
+                idx--;
+                assert stackAt(idx).getKind().needsTwoSlots();
+            }
+            idx--;
+        }
+        return stackAt(idx);
+    }
+
+    /**
+     * Clears all values on this stack.
+     */
+    public void clearStack() {
+        stackSize = 0;
+    }
+
+    private boolean assertLongPeek() {
+        return assertLong(xpeek());
+    }
+
+    private static boolean assertLong(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Long);
+        return true;
+    }
+
+    private boolean assertIntPeek() {
+        return assertInt(xpeek());
+    }
+
+    private static boolean assertInt(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Int);
+        return true;
+    }
+
+    private boolean assertFloatPeek() {
+        return assertFloat(xpeek());
+    }
+
+    private static boolean assertFloat(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Float);
+        return true;
+    }
+
+    private boolean assertObjectPeek() {
+        return assertObject(xpeek());
+    }
+
+    private boolean assertObject(ValueNode x) {
+        assert x != null && (!checkTypes || (x.getKind() == Kind.Object));
+        return true;
+    }
+
+    private boolean assertDoublePeek() {
+        return assertDouble(xpeek());
+    }
+
+    private static boolean assertDouble(ValueNode x) {
+        assert x != null && (x.getKind() == Kind.Double);
+        return true;
+    }
+
+    private boolean assertHighPeek() {
+        assert xpeek() == null;
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = hashCode(locals, locals.length);
+        result *= 13;
+        result += hashCode(stack, this.stackSize);
+        return result;
+    }
+
+    private static int hashCode(Object[] a, int length) {
+        int result = 1;
+        for (int i = 0; i < length; ++i) {
+            Object element = a[i];
+            result = 31 * result + (element == null ? 0 : System.identityHashCode(element));
+        }
+        return result;
+    }
+
+    private static boolean equals(ValueNode[] a, ValueNode[] b, int length) {
+        for (int i = 0; i < length; ++i) {
+            if (a[i] != b[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean equals(Object otherObject) {
+        if (otherObject instanceof HIRFrameStateBuilder) {
+            HIRFrameStateBuilder other = (HIRFrameStateBuilder) otherObject;
+            if (!other.method.equals(method)) {
+                return false;
+            }
+            if (other.stackSize != stackSize) {
+                return false;
+            }
+            if (other.checkTypes != checkTypes) {
+                return false;
+            }
+            if (other.rethrowException != rethrowException) {
+                return false;
+            }
+            if (other.graph != graph) {
+                return false;
+            }
+            if (other.outerFrameStateSupplier != outerFrameStateSupplier) {
+                return false;
+            }
+            if (other.locals.length != locals.length) {
+                return false;
+            }
+            return equals(other.locals, locals, locals.length) && equals(other.stack, stack, stackSize) && equals(other.lockedObjects, lockedObjects, lockedObjects.length) &&
+                            equals(other.monitorIds, monitorIds, monitorIds.length);
+        }
+        return false;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/InvocationPlugins.java	Mon Mar 02 19:11:22 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	Mon Mar 02 19:11:22 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	Mon Mar 02 19:11:22 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	Mon Mar 02 19:11:22 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/StandardGraphBuilderPlugins.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +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.java.GraphBuilderPlugins.InvocationPlugin;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration;
-import com.oracle.graal.java.GraphBuilderPlugins.Registration.Receiver;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-
-/**
- * Provider of non-runtime specific {@link GraphBuilderPlugin}s.
- */
-public class StandardGraphBuilderPlugins {
-    public static void registerPlugins(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-        Registration r = new Registration(plugins, metaAccess, Object.class);
-        r.register1("<init>", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext builder, ValueNode object) {
-                if (RegisterFinalizerNode.mayHaveFinalizer(object, builder.getAssumptions())) {
-                    builder.append(new RegisterFinalizerNode(object));
-                }
-                return true;
-            }
-        });
-
-        for (Kind kind : Kind.values()) {
-            if (kind.isPrimitive() && kind != Kind.Void) {
-                new BoxPlugin(kind).register(metaAccess, plugins);
-                new UnboxPlugin(kind).register(metaAccess, plugins);
-            }
-        }
-
-        GraalDirectivePlugins.registerPlugins(metaAccess, plugins);
-    }
-
-    static class BoxPlugin implements InvocationPlugin {
-
-        private final Kind kind;
-
-        BoxPlugin(Kind kind) {
-            this.kind = kind;
-        }
-
-        public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ResolvedJavaType resultType = builder.getMetaAccess().lookupJavaType(kind.toBoxedJavaClass());
-            builder.push(Kind.Object, builder.append(new BoxNode(value, resultType, kind)));
-            return true;
-        }
-
-        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), "valueOf", kind.toJavaClass());
-            plugins.register(method, this);
-        }
-    }
-
-    static class UnboxPlugin implements InvocationPlugin {
-
-        private final Kind kind;
-
-        UnboxPlugin(Kind kind) {
-            this.kind = kind;
-        }
-
-        public boolean apply(GraphBuilderContext builder, ValueNode value) {
-            ValueNode valueNode = UnboxNode.create(builder.getMetaAccess(), builder.getConstantReflection(), nullCheckedValue(builder, value), kind);
-            builder.push(kind.getStackKind(), builder.append(valueNode));
-            return true;
-        }
-
-        void register(MetaAccessProvider metaAccess, GraphBuilderPlugins plugins) {
-            String name = kind.toJavaClass().getSimpleName() + "Value";
-            ResolvedJavaMethod method = Registration.resolve(metaAccess, kind.toBoxedJavaClass(), name);
-            plugins.register(method, this);
-        }
-    }
-}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/UntrustedInterfaces.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/except/UntrustedInterfaces.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/hotspot/Test6753639.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/LongToSomethingArray01.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64AddressValue.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Arithmetic.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ArrayEqualsOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BitManipulationOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BreakpointOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ByteSwapOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CCall.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Call.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Compare.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ControlFlow.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64FrameMap.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64LIRInstruction.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MathIntrinsicOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RestoreRegistersOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64SaveRegistersOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestMemoryOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64TestOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ZapRegistersOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCAddressValue.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Mon Mar 02 19:11:22 2015 +0100
@@ -62,13 +62,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;
@@ -84,7 +86,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;
@@ -97,6 +100,7 @@
         }
 
         public BinaryRegReg(SPARCArithmetic opcode, Value result, Value x, Value y, LIRFrameState state) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -119,7 +123,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;
@@ -132,6 +137,7 @@
         }
 
         public BinaryRegConst(SPARCArithmetic opcode, AllocatableValue result, Value x, JavaConstant y, LIRFrameState state) {
+            super(TYPE);
             this.opcode = opcode;
             this.result = result;
             this.x = x;
@@ -154,7 +160,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;
@@ -165,6 +172,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;
@@ -189,7 +197,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;
@@ -197,6 +206,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;
@@ -841,7 +851,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;
@@ -850,6 +861,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArrayEqualsOp.java	Mon Mar 02 19:11:22 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
@@ -50,7 +50,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;
@@ -67,6 +68,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBitManipulationOp.java	Mon Mar 02 19:11:22 2015 +0100
@@ -35,7 +35,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,
@@ -51,6 +52,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCBreakpointOp.java	Mon Mar 02 19:11:22 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
@@ -33,7 +33,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
@@ -46,6 +47,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCByteSwapOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCall.java	Mon Mar 02 19:11:22 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,13 +37,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;
@@ -58,27 +60,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);
@@ -118,12 +125,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;
         }
 
@@ -140,11 +149,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;
         }
 
@@ -155,10 +165,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
@@ -168,10 +179,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCCompare.java	Mon Mar 02 19:11:22 2015 +0100
@@ -41,13 +41,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Mon Mar 02 19:11:22 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
@@ -51,11 +51,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;
         }
 
@@ -71,7 +73,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;
@@ -92,6 +95,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;
@@ -325,7 +329,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);
         protected final ConditionFlag conditionFlag;
         protected final LabelRef trueDestination;
         protected final LabelRef falseDestination;
@@ -333,6 +338,7 @@
         protected final double trueDestinationProbability;
 
         public BranchOp(ConditionFlag conditionFlag, LabelRef trueDestination, LabelRef falseDestination, Kind kind, double trueDestinationProbability) {
+            super(TYPE);
             this.trueDestination = trueDestination;
             this.falseDestination = falseDestination;
             this.kind = kind;
@@ -383,7 +389,8 @@
         return true;
     }
 
-    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;
@@ -392,6 +399,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;
@@ -443,7 +451,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;
@@ -452,6 +461,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;
@@ -514,7 +524,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;
 
@@ -526,6 +537,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCFrameMap.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCJumpOp.java	Mon Mar 02 19:11:22 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
@@ -30,12 +30,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCLIRInstruction.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMathIntrinsicOp.java	Mon Mar 02 19:11:22 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,7 +30,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,
@@ -47,6 +48,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Mon Mar 02 19:11:22 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,11 +45,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;
         }
@@ -71,12 +73,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;
         }
@@ -101,14 +105,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;
@@ -195,13 +200,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;
         }
@@ -248,12 +254,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;
@@ -275,12 +283,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;
         }
 
@@ -327,12 +336,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;
         }
@@ -344,12 +355,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;
         }
@@ -364,11 +377,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;
         }
 
@@ -378,12 +393,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;
         }
@@ -405,7 +422,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;
@@ -413,6 +431,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;
@@ -426,12 +445,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;
         }
@@ -462,11 +483,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;
         }
 
@@ -511,12 +533,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCSaveRegistersOp.java	Mon Mar 02 19:11:22 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
@@ -40,6 +40,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.
@@ -64,6 +65,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCTestOp.java	Mon Mar 02 19:11:22 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
@@ -29,14 +29,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest1.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest2.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest3.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/CompositeValueReplacementTest4.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest1.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest2.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir.test/src/com/oracle/graal/lir/test/ValuePositionTest3.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValue.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/CompositeValueClass.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/ControlFlowOptimizer.java	Mon Mar 02 19:11:22 2015 +0100
@@ -35,18 +35,18 @@
 /**
  * This class performs basic optimizations on the control flow graph after LIR generation.
  */
-public final class ControlFlowOptimizer extends LIRLowTierPhase {
+public final class ControlFlowOptimizer extends PostAllocationOptimizationPhase {
 
     /**
      * Performs control flow optimizations on the given LIR graph.
      */
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<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 final class Optimizer<B extends AbstractBlock<B>> {
+    private static final class Optimizer<B extends AbstractBlockBase<B>> {
 
         private final LIR lir;
 
@@ -97,7 +97,7 @@
                 if (canDeleteBlock(block)) {
                     // adjust successor and predecessor lists
                     B other = block.getSuccessors().iterator().next();
-                    for (AbstractBlock<B> pred : block.getPredecessors()) {
+                    for (AbstractBlockBase<B> pred : block.getPredecessors()) {
                         Collections.replaceAll(pred.getSuccessors(), block, other);
                     }
                     for (int i = 0; i < other.getPredecessorCount(); i++) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/EdgeMoveOptimizer.java	Mon Mar 02 19:11:22 2015 +0100
@@ -48,17 +48,17 @@
  * Because this optimization works best when a block contains only a few moves, it has a huge impact
  * on the number of blocks that are totally empty.
  */
-public final class EdgeMoveOptimizer extends LIRLowTierPhase {
+public final class EdgeMoveOptimizer extends PostAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<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();
+        List<? extends AbstractBlockBase<?>> blockList = ir.linearScanOrder();
         // ignore the first block in the list (index 0 is not processed)
         for (int i = blockList.size() - 1; i >= 1; i--) {
-            AbstractBlock<?> block = blockList.get(i);
+            AbstractBlockBase<?> block = blockList.get(i);
 
             if (block.getPredecessorCount() > 1) {
                 optimizer.optimizeMovesAtBlockEnd(block);
@@ -106,8 +106,8 @@
          * 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()) {
+        private void optimizeMovesAtBlockEnd(AbstractBlockBase<?> block) {
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
                 if (pred == block) {
                     // currently we can't handle this correctly.
                     return;
@@ -121,7 +121,7 @@
             assert numPreds > 1 : "do not call otherwise";
 
             // setup a list with the LIR instructions of all predecessors
-            for (AbstractBlock<?> pred : block.getPredecessors()) {
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
                 assert pred != null;
                 assert ir.getLIRforBlock(pred) != null;
                 List<LIRInstruction> predInstructions = ir.getLIRforBlock(pred);
@@ -176,7 +176,7 @@
          * {@code block} to the end of {@code block} just prior to the branch instruction ending
          * {@code block}.
          */
-        private void optimizeMovesAtBlockBegin(AbstractBlock<?> block) {
+        private void optimizeMovesAtBlockBegin(AbstractBlockBase<?> block) {
 
             edgeInstructionSeqences.clear();
             int numSux = block.getSuccessorCount();
@@ -206,7 +206,7 @@
             int insertIdx = instructions.size() - 1;
 
             // setup a list with the lir-instructions of all successors
-            for (AbstractBlock<?> sux : block.getSuccessors()) {
+            for (AbstractBlockBase<?> sux : block.getSuccessors()) {
                 List<LIRInstruction> suxInstructions = ir.getLIRforBlock(sux);
 
                 assert suxInstructions.get(0) instanceof StandardOp.LabelOp : "block must start with label";
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FullInfopointOp.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/FullInfopointOp.java	Mon Mar 02 19:11:22 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/LIR.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIR.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,7 +24,6 @@
 
 import java.util.*;
 
-import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.StandardOp.BlockEndOp;
 import com.oracle.graal.lir.StandardOp.LabelOp;
@@ -40,32 +39,25 @@
     /**
      * The linear-scan ordered list of blocks.
      */
-    private final List<? extends AbstractBlock<?>> linearScanOrder;
+    private final List<? extends AbstractBlockBase<?>> linearScanOrder;
 
     /**
      * The order in which the code is emitted.
      */
-    private final List<? extends AbstractBlock<?>> codeEmittingOrder;
+    private final List<? extends AbstractBlockBase<?>> codeEmittingOrder;
 
     private int firstVariableNumber;
 
     private int numVariables;
 
-    private SpillMoveFactory spillMoveFactory;
-
     private final BlockMap<List<LIRInstruction>> lirInstructions;
 
-    public interface SpillMoveFactory {
-
-        LIRInstruction createMove(AllocatableValue result, Value input);
-    }
-
     private boolean hasArgInCallerFrame;
 
     /**
      * Creates a new LIR instance for the specified compilation.
      */
-    public LIR(AbstractControlFlowGraph<?> cfg, List<? extends AbstractBlock<?>> linearScanOrder, List<? extends AbstractBlock<?>> codeEmittingOrder) {
+    public LIR(AbstractControlFlowGraph<?> cfg, List<? extends AbstractBlockBase<?>> linearScanOrder, List<? extends AbstractBlockBase<?>> codeEmittingOrder) {
         this.cfg = cfg;
         this.codeEmittingOrder = codeEmittingOrder;
         this.linearScanOrder = linearScanOrder;
@@ -80,7 +72,7 @@
      * Determines if any instruction in the LIR has debug info associated with it.
      */
     public boolean hasDebugInfo() {
-        for (AbstractBlock<?> b : linearScanOrder()) {
+        for (AbstractBlockBase<?> b : linearScanOrder()) {
             for (LIRInstruction op : getLIRforBlock(b)) {
                 if (op.hasState()) {
                     return true;
@@ -90,15 +82,11 @@
         return false;
     }
 
-    public SpillMoveFactory getSpillMoveFactory() {
-        return spillMoveFactory;
-    }
-
-    public List<LIRInstruction> getLIRforBlock(AbstractBlock<?> block) {
+    public List<LIRInstruction> getLIRforBlock(AbstractBlockBase<?> block) {
         return lirInstructions.get(block);
     }
 
-    public void setLIRforBlock(AbstractBlock<?> block, List<LIRInstruction> list) {
+    public void setLIRforBlock(AbstractBlockBase<?> block, List<LIRInstruction> list) {
         assert getLIRforBlock(block) == null : "lir instruction list should only be initialized once";
         lirInstructions.put(block, list);
     }
@@ -108,11 +96,11 @@
      *
      * @return the blocks in linear scan order
      */
-    public List<? extends AbstractBlock<?>> linearScanOrder() {
+    public List<? extends AbstractBlockBase<?>> linearScanOrder() {
         return linearScanOrder;
     }
 
-    public List<? extends AbstractBlock<?>> codeEmittingOrder() {
+    public List<? extends AbstractBlockBase<?>> codeEmittingOrder() {
         return codeEmittingOrder;
     }
 
@@ -166,7 +154,7 @@
      */
     public static final int MAX_EXCEPTION_EDGE_OP_DISTANCE_FROM_END = 3;
 
-    public static boolean verifyBlock(LIR lir, AbstractBlock<?> block) {
+    public static boolean verifyBlock(LIR lir, AbstractBlockBase<?> block) {
         List<LIRInstruction> ops = lir.getLIRforBlock(block);
         if (ops.size() == 0) {
             return false;
@@ -190,12 +178,12 @@
         return true;
     }
 
-    public static boolean verifyBlocks(LIR lir, List<? extends AbstractBlock<?>> blocks) {
-        for (AbstractBlock<?> block : blocks) {
-            for (AbstractBlock<?> sux : block.getSuccessors()) {
+    public static boolean verifyBlocks(LIR lir, List<? extends AbstractBlockBase<?>> blocks) {
+        for (AbstractBlockBase<?> block : blocks) {
+            for (AbstractBlockBase<?> sux : block.getSuccessors()) {
                 assert blocks.contains(sux) : "missing successor from: " + block + "to: " + sux;
             }
-            for (AbstractBlock<?> pred : block.getPredecessors()) {
+            for (AbstractBlockBase<?> pred : block.getPredecessors()) {
                 assert blocks.contains(pred) : "missing predecessor from: " + block + "to: " + pred;
             }
             if (!verifyBlock(lir, block)) {
@@ -205,13 +193,9 @@
         return true;
     }
 
-    public void setSpillMoveFactory(SpillMoveFactory spillMoveFactory) {
-        this.spillMoveFactory = spillMoveFactory;
-    }
-
     public void resetLabels() {
 
-        for (AbstractBlock<?> block : codeEmittingOrder()) {
+        for (AbstractBlockBase<?> block : codeEmittingOrder()) {
             for (LIRInstruction inst : lirInstructions.get(block)) {
                 if (inst instanceof LabelOp) {
                     ((LabelOp) inst).getLabel().reset();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstruction.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRInstructionClass.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRIntrospection.java	Mon Mar 02 19:11:22 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/LIRVerifier.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LIRVerifier.java	Mon Mar 02 19:11:22 2015 +0100
@@ -46,11 +46,11 @@
     private final BitSet[] blockLiveOut;
     private final Object[] variableDefinitions;
 
-    private BitSet liveOutFor(AbstractBlock<?> block) {
+    private BitSet liveOutFor(AbstractBlockBase<?> block) {
         return blockLiveOut[block.getId()];
     }
 
-    private void setLiveOutFor(AbstractBlock<?> block, BitSet liveOut) {
+    private void setLiveOutFor(AbstractBlockBase<?> block, BitSet liveOut) {
         blockLiveOut[block.getId()] = liveOut;
     }
 
@@ -91,7 +91,7 @@
     private BitSet curVariablesLive;
     private Value[] curRegistersLive;
 
-    private AbstractBlock<?> curBlock;
+    private AbstractBlockBase<?> curBlock;
     private Object curInstruction;
     private BitSet curRegistersDefined;
 
@@ -113,7 +113,7 @@
 
         int maxRegisterNum = maxRegisterNum();
         curRegistersDefined = new BitSet();
-        for (AbstractBlock<?> block : lir.linearScanOrder()) {
+        for (AbstractBlockBase<?> block : lir.linearScanOrder()) {
             curBlock = block;
             curVariablesLive = new BitSet();
             curRegistersLive = new Value[maxRegisterNum];
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/LabelRef.java	Mon Mar 02 19:11:22 2015 +0100
@@ -29,16 +29,17 @@
 
 /**
  * LIR instructions such as {@link JumpOp} and {@link BranchOp} need to reference their target
- * {@link AbstractBlock}. However, direct references are not possible since the control flow graph
- * (and therefore successors lists) can be changed by optimizations - and fixing the instructions is
- * error prone. Therefore, we represent an edge to block B from block A via the tuple {@code (A,
+ * {@link AbstractBlockBase}. However, direct references are not possible since the control flow
+ * graph (and therefore successors lists) can be changed by optimizations - and fixing the
+ * instructions is error prone. Therefore, we represent an edge to block B from block A via the
+ * tuple {@code (A,
  * successor-index-of-B)}. That is, indirectly by storing the index into the successor list of A.
  * Note therefore that the successor list cannot be re-ordered.
  */
 public final class LabelRef {
 
     private final LIR lir;
-    private final AbstractBlock<?> block;
+    private final AbstractBlockBase<?> block;
     private final int suxIndex;
 
     /**
@@ -48,7 +49,7 @@
      * @param suxIndex The index of the successor.
      * @return The newly created label reference.
      */
-    public static LabelRef forSuccessor(final LIR lir, final AbstractBlock<?> block, final int suxIndex) {
+    public static LabelRef forSuccessor(final LIR lir, final AbstractBlockBase<?> block, final int suxIndex) {
         return new LabelRef(lir, block, suxIndex);
     }
 
@@ -58,17 +59,17 @@
      * @param block The base block that contains the successor list.
      * @param suxIndex The index of the successor.
      */
-    private LabelRef(final LIR lir, final AbstractBlock<?> block, final int suxIndex) {
+    private LabelRef(final LIR lir, final AbstractBlockBase<?> block, final int suxIndex) {
         this.lir = lir;
         this.block = block;
         this.suxIndex = suxIndex;
     }
 
-    public AbstractBlock<?> getSourceBlock() {
+    public AbstractBlockBase<?> getSourceBlock() {
         return block;
     }
 
-    public AbstractBlock<?> getTargetBlock() {
+    public AbstractBlockBase<?> getTargetBlock() {
         return block.getSuccessors().get(suxIndex);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/NullCheckOptimizer.java	Mon Mar 02 19:11:22 2015 +0100
@@ -31,17 +31,17 @@
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.lir.phases.*;
 
-public final class NullCheckOptimizer extends LIRLowTierPhase {
+public final class NullCheckOptimizer extends PostAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
         LIR ir = lirGenRes.getLIR();
-        List<? extends AbstractBlock<?>> blocks = ir.codeEmittingOrder();
+        List<? extends AbstractBlockBase<?>> blocks = ir.codeEmittingOrder();
         NullCheckOptimizer.foldNullChecks(ir, blocks, target.implicitNullCheckLimit);
     }
 
-    private static void foldNullChecks(LIR ir, List<? extends AbstractBlock<?>> blocks, int implicitNullCheckLimit) {
-        for (AbstractBlock<?> block : blocks) {
+    private static void foldNullChecks(LIR ir, List<? extends AbstractBlockBase<?>> blocks, int implicitNullCheckLimit) {
+        for (AbstractBlockBase<?> block : blocks) {
             List<LIRInstruction> list = ir.getLIRforBlock(block);
 
             if (!list.isEmpty()) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/RedundantMoveElimination.java	Mon Mar 02 19:11:22 2015 +0100
@@ -41,10 +41,10 @@
 /**
  * Removes move instructions, where the destination value is already in place.
  */
-public final class RedundantMoveElimination extends LIRLowTierPhase {
+public final class RedundantMoveElimination extends PostAllocationOptimizationPhase {
 
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
         Optimization redundantMoveElimination = new Optimization();
         redundantMoveElimination.doOptimize(lirGenRes.getLIR(), lirGenRes.getFrameMap());
     }
@@ -87,7 +87,7 @@
 
     private static final class Optimization {
 
-        Map<AbstractBlock<?>, BlockData> blockData = CollectionsFactory.newMap();
+        Map<AbstractBlockBase<?>, BlockData> blockData = CollectionsFactory.newMap();
 
         Register[] callerSaveRegs;
 
@@ -142,7 +142,7 @@
 
         private void initBlockData(LIR lir) {
 
-            List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+            List<? extends AbstractBlockBase<?>> blocks = lir.linearScanOrder();
             numRegs = 0;
 
             int maxStackLocations = COMPLEXITY_LIMIT / blocks.size();
@@ -151,7 +151,7 @@
              * 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) {
+            for (AbstractBlockBase<?> block : blocks) {
                 List<LIRInstruction> instructions = lir.getLIRforBlock(block);
                 for (LIRInstruction op : instructions) {
                     if (isEligibleMove(op)) {
@@ -176,7 +176,7 @@
              */
             int numLocations = numRegs + stackIndices.size();
             Debug.log("num locations = %d (regs = %d, stack = %d)", numLocations, numRegs, stackIndices.size());
-            for (AbstractBlock<?> block : blocks) {
+            for (AbstractBlockBase<?> block : blocks) {
                 BlockData data = new BlockData(numLocations);
                 blockData.put(block, data);
             }
@@ -191,7 +191,7 @@
 
             try (Indent indent = Debug.logAndIndent("solve data flow")) {
 
-                List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+                List<? extends AbstractBlockBase<?>> blocks = lir.linearScanOrder();
 
                 int numIter = 0;
 
@@ -205,7 +205,7 @@
                     changed = false;
                     try (Indent indent2 = Debug.logAndIndent("new iteration")) {
 
-                        for (AbstractBlock<?> block : blocks) {
+                        for (AbstractBlockBase<?> block : blocks) {
 
                             BlockData data = blockData.get(block);
                             /*
@@ -235,7 +235,7 @@
                                 /*
                                  * Merge the states of predecessor blocks
                                  */
-                                for (AbstractBlock<?> predecessor : block.getPredecessors()) {
+                                for (AbstractBlockBase<?> predecessor : block.getPredecessors()) {
                                     BlockData predData = blockData.get(predecessor);
                                     newState |= mergeState(data.entryState, predData.exitState, valueNum);
                                 }
@@ -291,9 +291,9 @@
 
             try (Indent indent = Debug.logAndIndent("eliminate moves")) {
 
-                List<? extends AbstractBlock<?>> blocks = lir.linearScanOrder();
+                List<? extends AbstractBlockBase<?>> blocks = lir.linearScanOrder();
 
-                for (AbstractBlock<?> block : blocks) {
+                for (AbstractBlockBase<?> block : blocks) {
 
                     try (Indent indent2 = Debug.logAndIndent("eliminate moves in block %d", block.getId())) {
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SimpleInfopointOp.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/StandardOp.java	Mon Mar 02 19:11:22 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,19 +186,21 @@
      * 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.
          */
-        final AbstractBlock<?> block;
+        final AbstractBlockBase<?> block;
 
         /**
          * The block index of this instruction.
          */
         final int index;
 
-        public NoOp(AbstractBlock<?> block, int index) {
+        public NoOp(AbstractBlockBase<?> 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/SwitchStrategy.java	Mon Mar 02 19:11:22 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/IntervalWalker.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/IntervalWalker.java	Mon Mar 02 19:11:22 2015 +0100
@@ -104,63 +104,65 @@
     private void walkTo(State state, int from) {
         assert state == State.Active || state == State.Inactive : "wrong state";
         for (RegisterBinding binding : RegisterBinding.VALUES) {
-            Interval prevprev = null;
-            Interval prev = (state == State.Active) ? activeLists.get(binding) : inactiveLists.get(binding);
-            Interval next = prev;
-            while (next.currentFrom() <= from) {
-                Interval cur = next;
-                next = cur.next;
+            walkTo(state, from, binding);
+        }
+    }
 
-                boolean rangeHasChanged = false;
-                while (cur.currentTo() <= from) {
-                    cur.nextRange();
-                    rangeHasChanged = true;
-                }
+    private void walkTo(State state, int from, RegisterBinding binding) {
+        Interval prevprev = null;
+        Interval prev = (state == State.Active) ? activeLists.get(binding) : inactiveLists.get(binding);
+        Interval next = prev;
+        while (next.currentFrom() <= from) {
+            Interval cur = next;
+            next = cur.next;
 
-                // also handle move from inactive list to active list
-                rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
+            boolean rangeHasChanged = false;
+            while (cur.currentTo() <= from) {
+                cur.nextRange();
+                rangeHasChanged = true;
+            }
 
-                if (rangeHasChanged) {
-                    // remove cur from list
-                    if (prevprev == null) {
-                        if (state == State.Active) {
-                            activeLists.set(binding, next);
-                        } else {
-                            inactiveLists.set(binding, next);
-                        }
+            // also handle move from inactive list to active list
+            rangeHasChanged = rangeHasChanged || (state == State.Inactive && cur.currentFrom() <= from);
+
+            if (rangeHasChanged) {
+                // remove cur from list
+                if (prevprev == null) {
+                    if (state == State.Active) {
+                        activeLists.set(binding, next);
                     } else {
-                        prevprev.next = next;
+                        inactiveLists.set(binding, next);
                     }
-                    prev = next;
-                    if (cur.currentAtEnd()) {
-                        // move to handled state (not maintained as a list)
-                        cur.state = State.Handled;
-                        intervalMoved(cur, state, State.Handled);
-                    } else if (cur.currentFrom() <= from) {
+                } else {
+                    prevprev.next = next;
+                }
+                prev = next;
+                Interval.State newState;
+                if (cur.currentAtEnd()) {
+                    // move to handled state (not maintained as a list)
+                    newState = State.Handled;
+                    cur.state = newState;
+                } else {
+                    if (cur.currentFrom() <= from) {
                         // sort into active list
                         activeLists.addToListSortedByCurrentFromPositions(binding, cur);
-                        cur.state = State.Active;
-                        if (prev == cur) {
-                            assert state == State.Active : "check";
-                            prevprev = prev;
-                            prev = cur.next;
-                        }
-                        intervalMoved(cur, state, State.Active);
+                        newState = State.Active;
                     } else {
                         // sort into inactive list
                         inactiveLists.addToListSortedByCurrentFromPositions(binding, cur);
-                        cur.state = State.Inactive;
-                        if (prev == cur) {
-                            assert state == State.Inactive : "check";
-                            prevprev = prev;
-                            prev = cur.next;
-                        }
-                        intervalMoved(cur, state, State.Inactive);
+                        newState = State.Inactive;
                     }
-                } else {
-                    prevprev = prev;
-                    prev = cur.next;
+                    cur.state = newState;
+                    if (prev == cur) {
+                        assert state == newState;
+                        prevprev = prev;
+                        prev = cur.next;
+                    }
                 }
+                intervalMoved(cur, state, newState);
+            } else {
+                prevprev = prev;
+                prev = cur.next;
             }
         }
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScan.java	Mon Mar 02 19:11:22 2015 +0100
@@ -48,6 +48,7 @@
 import com.oracle.graal.lir.alloc.lsra.Interval.SpillState;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.options.*;
 
 /**
@@ -62,6 +63,7 @@
     final LIRGenerationResult res;
     final LIR ir;
     final FrameMapBuilder frameMapBuilder;
+    final SpillMoveFactory spillMoveFactory;
     final RegisterAttributes[] registerAttributes;
     final Register[] registers;
 
@@ -114,7 +116,7 @@
     /**
      * List of blocks in linear-scan order. This is only correct as long as the CFG does not change.
      */
-    final List<? extends AbstractBlock<?>> sortedBlocks;
+    final List<? extends AbstractBlockBase<?>> sortedBlocks;
 
     /**
      * Map from {@linkplain #operandNumber(Value) operand numbers} to intervals.
@@ -145,11 +147,11 @@
     LIRInstruction[] opIdToInstructionMap;
 
     /**
-     * Map from an instruction {@linkplain LIRInstruction#id id} to the {@linkplain AbstractBlock
-     * block} containing the instruction. Entries should be retrieved with {@link #blockForId(int)}
-     * as the id is not simply an index into this array.
+     * Map from an instruction {@linkplain LIRInstruction#id id} to the
+     * {@linkplain AbstractBlockBase block} containing the instruction. Entries should be retrieved
+     * with {@link #blockForId(int)} as the id is not simply an index into this array.
      */
-    AbstractBlock<?>[] opIdToBlockMap;
+    AbstractBlockBase<?>[] opIdToBlockMap;
 
     /**
      * Bit set for each variable that is contained in each loop.
@@ -161,10 +163,11 @@
      */
     private final int firstVariableNumber;
 
-    LinearScan(TargetDescription target, LIRGenerationResult res) {
+    LinearScan(TargetDescription target, LIRGenerationResult res, SpillMoveFactory spillMoveFactory) {
         this.target = target;
         this.res = res;
         this.ir = res.getLIR();
+        this.spillMoveFactory = spillMoveFactory;
         this.frameMapBuilder = res.getFrameMapBuilder();
         this.sortedBlocks = ir.linearScanOrder();
         this.registerAttributes = frameMapBuilder.getRegisterConfig().getAttributesMap();
@@ -178,19 +181,23 @@
         this.callKillsRegisters = this.frameMapBuilder.getRegisterConfig().areAllAllocatableRegistersCallerSaved();
     }
 
-    int getFirstLirInstructionId(AbstractBlock<?> block) {
+    int getFirstLirInstructionId(AbstractBlockBase<?> block) {
         int result = ir.getLIRforBlock(block).get(0).id();
         assert result >= 0;
         return result;
     }
 
-    int getLastLirInstructionId(AbstractBlock<?> block) {
+    int getLastLirInstructionId(AbstractBlockBase<?> block) {
         List<LIRInstruction> instructions = ir.getLIRforBlock(block);
         int result = instructions.get(instructions.size() - 1).id();
         assert result >= 0;
         return result;
     }
 
+    SpillMoveFactory getSpillMoveFactory() {
+        return spillMoveFactory;
+    }
+
     public static boolean isVariableOrRegister(Value value) {
         return isVariable(value) || isRegister(value);
     }
@@ -312,7 +319,7 @@
         return sortedBlocks.size();
     }
 
-    AbstractBlock<?> blockAt(int index) {
+    AbstractBlockBase<?> blockAt(int index) {
         return sortedBlocks.get(index);
     }
 
@@ -388,7 +395,7 @@
      * @param opId an instruction {@linkplain LIRInstruction#id id}
      * @return the block containing the instruction denoted by {@code opId}
      */
-    AbstractBlock<?> blockForId(int opId) {
+    AbstractBlockBase<?> blockForId(int opId) {
         assert opIdToBlockMap.length > 0 && opId >= 0 && opId <= maxOpId() + 1 : "opId out of range";
         return opIdToBlockMap[opIdToIndex(opId)];
     }
@@ -522,7 +529,7 @@
             }
 
             LIRInsertionBuffer insertionBuffer = new LIRInsertionBuffer();
-            for (AbstractBlock<?> block : sortedBlocks) {
+            for (AbstractBlockBase<?> block : sortedBlocks) {
                 List<LIRInstruction> instructions = ir.getLIRforBlock(block);
                 int numInst = instructions.size();
 
@@ -571,7 +578,7 @@
                                 assert isRegister(fromLocation) : "from operand must be a register but is: " + fromLocation + " toLocation=" + toLocation + " spillState=" + interval.spillState();
                                 assert isStackSlotValue(toLocation) : "to operand must be a stack slot";
 
-                                insertionBuffer.append(j + 1, ir.getSpillMoveFactory().createMove(toLocation, fromLocation));
+                                insertionBuffer.append(j + 1, getSpillMoveFactory().createMove(toLocation, fromLocation));
 
                                 Debug.log("inserting move after definition of interval %d to stack slot %s at opId %d", interval.operandNumber, interval.spillSlot(), opId);
                             }
@@ -627,17 +634,17 @@
 
         // Assign IDs to LIR nodes and build a mapping, lirOps, from ID to LIRInstruction node.
         int numInstructions = 0;
-        for (AbstractBlock<?> block : sortedBlocks) {
+        for (AbstractBlockBase<?> block : sortedBlocks) {
             numInstructions += ir.getLIRforBlock(block).size();
         }
 
         // initialize with correct length
         opIdToInstructionMap = new LIRInstruction[numInstructions];
-        opIdToBlockMap = new AbstractBlock<?>[numInstructions];
+        opIdToBlockMap = new AbstractBlockBase<?>[numInstructions];
 
         int opId = 0;
         int index = 0;
-        for (AbstractBlock<?> block : sortedBlocks) {
+        for (AbstractBlockBase<?> block : sortedBlocks) {
             blockData.put(block, new BlockData());
 
             List<LIRInstruction> instructions = ir.getLIRforBlock(block);
@@ -672,7 +679,7 @@
         intervalInLoop = new BitMap2D(operandSize(), numLoops());
 
         // iterate all blocks
-        for (final AbstractBlock<?> block : sortedBlocks) {
+        for (final AbstractBlockBase<?> block : sortedBlocks) {
             try (Indent indent = Debug.logAndIndent("compute local live sets for block %d", block.getId())) {
 
                 final BitSet liveGen = new BitSet(liveSize);
@@ -763,7 +770,7 @@
         }
     }
 
-    private void verifyInput(AbstractBlock<?> block, BitSet liveKill, Value operand) {
+    private void verifyInput(AbstractBlockBase<?> block, BitSet liveKill, Value operand) {
         // fixed intervals are never live at block boundaries, so
         // they need not be processed in live sets.
         // this is checked by these assertions to be sure about it.
@@ -797,7 +804,7 @@
 
                     // iterate all blocks in reverse order
                     for (int i = numBlocks - 1; i >= 0; i--) {
-                        AbstractBlock<?> block = blockAt(i);
+                        AbstractBlockBase<?> block = blockAt(i);
                         BlockData blockSets = blockData.get(block);
 
                         changeOccurredInBlock = false;
@@ -808,7 +815,7 @@
                             liveOut.clear();
                             // block has successors
                             if (n > 0) {
-                                for (AbstractBlock<?> successor : block.getSuccessors()) {
+                                for (AbstractBlockBase<?> successor : block.getSuccessors()) {
                                     liveOut.or(blockData.get(successor).liveIn);
                                 }
                             }
@@ -852,7 +859,7 @@
             }
 
             // check that the liveIn set of the first block is empty
-            AbstractBlock<?> startBlock = ir.getControlFlowGraph().getStartBlock();
+            AbstractBlockBase<?> startBlock = ir.getControlFlowGraph().getStartBlock();
             if (blockData.get(startBlock).liveIn.cardinality() != 0) {
                 if (DetailedAsserts.getValue()) {
                     reportFailure(numBlocks);
@@ -891,9 +898,9 @@
                     }
                     try (Indent indent2 = Debug.logAndIndent("---- Detailed information for var %d; operand=%s; node=%s ----", operandNum, operand, valueForOperandFromDebugContext)) {
 
-                        Deque<AbstractBlock<?>> definedIn = new ArrayDeque<>();
-                        HashSet<AbstractBlock<?>> usedIn = new HashSet<>();
-                        for (AbstractBlock<?> block : sortedBlocks) {
+                        Deque<AbstractBlockBase<?>> definedIn = new ArrayDeque<>();
+                        HashSet<AbstractBlockBase<?>> usedIn = new HashSet<>();
+                        for (AbstractBlockBase<?> block : sortedBlocks) {
                             if (blockData.get(block).liveGen.get(operandNum)) {
                                 usedIn.add(block);
                                 try (Indent indent3 = Debug.logAndIndent("used in block B%d", block.getId())) {
@@ -920,9 +927,9 @@
                         int[] hitCount = new int[numBlocks];
 
                         while (!definedIn.isEmpty()) {
-                            AbstractBlock<?> block = definedIn.removeFirst();
+                            AbstractBlockBase<?> block = definedIn.removeFirst();
                             usedIn.remove(block);
-                            for (AbstractBlock<?> successor : block.getSuccessors()) {
+                            for (AbstractBlockBase<?> successor : block.getSuccessors()) {
                                 if (successor.isLoopHeader()) {
                                     if (!block.isLoopEnd()) {
                                         definedIn.add(successor);
@@ -935,7 +942,7 @@
                             }
                         }
                         try (Indent indent3 = Debug.logAndIndent("**** offending usages are in: ")) {
-                            for (AbstractBlock<?> block : usedIn) {
+                            for (AbstractBlockBase<?> block : usedIn) {
                                 Debug.log("B%d", block.getId());
                             }
                         }
@@ -950,7 +957,7 @@
     private void verifyLiveness() {
         // check that fixed intervals are not live at block boundaries
         // (live set must be empty at fixed intervals)
-        for (AbstractBlock<?> block : sortedBlocks) {
+        for (AbstractBlockBase<?> block : sortedBlocks) {
             for (int j = 0; j <= maxRegisterNumber(); j++) {
                 assert !blockData.get(block).liveIn.get(j) : "liveIn  set of fixed register must be empty";
                 assert !blockData.get(block).liveOut.get(j) : "liveOut set of fixed register must be empty";
@@ -1167,7 +1174,7 @@
             // iterate all blocks in reverse order
             for (int i = blockCount() - 1; i >= 0; i--) {
 
-                AbstractBlock<?> block = blockAt(i);
+                AbstractBlockBase<?> block = blockAt(i);
                 try (Indent indent2 = Debug.logAndIndent("handle block %d", block.getId())) {
 
                     List<LIRInstruction> instructions = ir.getLIRforBlock(block);
@@ -1411,15 +1418,15 @@
         throw new BailoutException("LinearScan: interval is null");
     }
 
-    Interval intervalAtBlockBegin(AbstractBlock<?> block, int operandNumber) {
+    Interval intervalAtBlockBegin(AbstractBlockBase<?> block, int operandNumber) {
         return splitChildAtOpId(intervalFor(operandNumber), getFirstLirInstructionId(block), LIRInstruction.OperandMode.DEF);
     }
 
-    Interval intervalAtBlockEnd(AbstractBlock<?> block, int operandNumber) {
+    Interval intervalAtBlockEnd(AbstractBlockBase<?> block, int operandNumber) {
         return splitChildAtOpId(intervalFor(operandNumber), getLastLirInstructionId(block) + 1, LIRInstruction.OperandMode.DEF);
     }
 
-    void resolveCollectMappings(AbstractBlock<?> fromBlock, AbstractBlock<?> toBlock, MoveResolver moveResolver) {
+    void resolveCollectMappings(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
         assert moveResolver.checkEmpty();
 
         int numOperands = operandSize();
@@ -1440,7 +1447,7 @@
         }
     }
 
-    void resolveFindInsertPos(AbstractBlock<?> fromBlock, AbstractBlock<?> toBlock, MoveResolver moveResolver) {
+    void resolveFindInsertPos(AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock, MoveResolver moveResolver) {
         if (fromBlock.getSuccessorCount() <= 1) {
             Debug.log("inserting moves at end of fromBlock B%d", fromBlock.getId());
 
@@ -1463,7 +1470,7 @@
                 // successor edges, blocks which are reached by switch statements
                 // may have be more than one predecessor but it will be guaranteed
                 // that all predecessors will be the same.
-                for (AbstractBlock<?> predecessor : toBlock.getPredecessors()) {
+                for (AbstractBlockBase<?> predecessor : toBlock.getPredecessors()) {
                     assert fromBlock == predecessor : "all critical edges must be broken";
                 }
             }
@@ -1484,7 +1491,7 @@
             BitSet blockCompleted = new BitSet(numBlocks);
             BitSet alreadyResolved = new BitSet(numBlocks);
 
-            for (AbstractBlock<?> block : sortedBlocks) {
+            for (AbstractBlockBase<?> block : sortedBlocks) {
 
                 // check if block has only one predecessor and only one successor
                 if (block.getPredecessorCount() == 1 && block.getSuccessorCount() == 1) {
@@ -1494,8 +1501,8 @@
 
                     // check if block is empty (only label and branch)
                     if (instructions.size() == 2) {
-                        AbstractBlock<?> pred = block.getPredecessors().iterator().next();
-                        AbstractBlock<?> sux = block.getSuccessors().iterator().next();
+                        AbstractBlockBase<?> pred = block.getPredecessors().iterator().next();
+                        AbstractBlockBase<?> sux = block.getSuccessors().iterator().next();
 
                         // prevent optimization of two consecutive blocks
                         if (!blockCompleted.get(pred.getLinearScanNumber()) && !blockCompleted.get(sux.getLinearScanNumber())) {
@@ -1516,12 +1523,12 @@
                 }
             }
 
-            for (AbstractBlock<?> fromBlock : sortedBlocks) {
+            for (AbstractBlockBase<?> fromBlock : sortedBlocks) {
                 if (!blockCompleted.get(fromBlock.getLinearScanNumber())) {
                     alreadyResolved.clear();
                     alreadyResolved.or(blockCompleted);
 
-                    for (AbstractBlock<?> toBlock : fromBlock.getSuccessors()) {
+                    for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
 
                         // check for duplicate edges between the same blocks (can happen with switch
                         // blocks)
@@ -1566,7 +1573,7 @@
 
         if (opId != -1) {
             if (DetailedAsserts.getValue()) {
-                AbstractBlock<?> block = blockForId(opId);
+                AbstractBlockBase<?> block = blockForId(opId);
                 if (block.getSuccessorCount() <= 1 && opId == getLastLirInstructionId(block)) {
                     // check if spill moves could have been appended at the end of this block, but
                     // before the branch instruction. So the split child information for this branch
@@ -1639,7 +1646,7 @@
         }
         int tempOpId = op.id();
         OperandMode mode = OperandMode.USE;
-        AbstractBlock<?> block = blockForId(tempOpId);
+        AbstractBlockBase<?> block = blockForId(tempOpId);
         if (block.getSuccessorCount() == 1 && tempOpId == getLastLirInstructionId(block)) {
             // generating debug information for the last instruction of a block.
             // if this instruction is a branch, spill moves are inserted before this branch
@@ -1723,7 +1730,7 @@
 
     private void assignLocations() {
         try (Indent indent = Debug.logAndIndent("assign locations")) {
-            for (AbstractBlock<?> block : sortedBlocks) {
+            for (AbstractBlockBase<?> block : sortedBlocks) {
                 try (Indent indent2 = Debug.logAndIndent("assign locations in block B%d", block.getId())) {
                     assignLocations(ir.getLIRforBlock(block));
                 }
@@ -1811,8 +1818,8 @@
         LIRInsertionBuffer[] insertionBuffers = new LIRInsertionBuffer[ir.linearScanOrder().size()];
         for (Interval interval : intervals) {
             if (interval != null && interval.isSplitParent() && interval.spillState() == SpillState.SpillInDominator) {
-                AbstractBlock<?> defBlock = blockForId(interval.spillDefinitionPos());
-                AbstractBlock<?> spillBlock = null;
+                AbstractBlockBase<?> defBlock = blockForId(interval.spillDefinitionPos());
+                AbstractBlockBase<?> spillBlock = null;
                 Interval firstSpillChild = null;
                 try (Indent indent = Debug.logAndIndent("interval %s (%s)", interval, defBlock)) {
                     for (Interval splitChild : interval.getSplitChildren()) {
@@ -1823,7 +1830,7 @@
                                 assert firstSpillChild.from() < splitChild.from();
                             }
                             // iterate all blocks where the interval has use positions
-                            for (AbstractBlock<?> splitBlock : blocksForInterval(splitChild)) {
+                            for (AbstractBlockBase<?> splitBlock : blocksForInterval(splitChild)) {
                                 if (dominates(defBlock, splitBlock)) {
                                     Debug.log("Split interval %s, block %s", splitChild, splitBlock);
                                     if (spillBlock == null) {
@@ -1851,7 +1858,7 @@
                          */
                         assert firstSpillChild != null;
                         if (!defBlock.equals(spillBlock) && spillBlock.equals(blockForId(firstSpillChild.from()))) {
-                            AbstractBlock<?> dom = spillBlock.getDominator();
+                            AbstractBlockBase<?> dom = spillBlock.getDominator();
                             Debug.log("Spill block (%s) is the beginning of a spill child -> use dominator (%s)", spillBlock, dom);
                             spillBlock = dom;
                         }
@@ -1875,7 +1882,7 @@
                                 // insert spill move
                                 AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, this).location();
                                 AllocatableValue toLocation = canonicalSpillOpr(interval);
-                                LIRInstruction move = ir.getSpillMoveFactory().createMove(toLocation, fromLocation);
+                                LIRInstruction move = getSpillMoveFactory().createMove(toLocation, fromLocation);
                                 move.setId(DOMINATOR_SPILL_MOVE_ID);
                                 /*
                                  * We can use the insertion buffer directly because we always insert
@@ -1903,20 +1910,20 @@
     }
 
     /**
-     * Iterate over all {@link AbstractBlock blocks} of an interval.
+     * Iterate over all {@link AbstractBlockBase blocks} of an interval.
      */
-    private class IntervalBlockIterator implements Iterator<AbstractBlock<?>> {
+    private class IntervalBlockIterator implements Iterator<AbstractBlockBase<?>> {
 
         Range range;
-        AbstractBlock<?> block;
+        AbstractBlockBase<?> block;
 
         public IntervalBlockIterator(Interval interval) {
             range = interval.first();
             block = blockForId(range.from);
         }
 
-        public AbstractBlock<?> next() {
-            AbstractBlock<?> currentBlock = block;
+        public AbstractBlockBase<?> next() {
+            AbstractBlockBase<?> currentBlock = block;
             int nextBlockIndex = block.getLinearScanNumber() + 1;
             if (nextBlockIndex < sortedBlocks.size()) {
                 block = sortedBlocks.get(nextBlockIndex);
@@ -1939,17 +1946,17 @@
         }
     }
 
-    private Iterable<AbstractBlock<?>> blocksForInterval(Interval interval) {
-        return new Iterable<AbstractBlock<?>>() {
-            public Iterator<AbstractBlock<?>> iterator() {
+    private Iterable<AbstractBlockBase<?>> blocksForInterval(Interval interval) {
+        return new Iterable<AbstractBlockBase<?>>() {
+            public Iterator<AbstractBlockBase<?>> iterator() {
                 return new IntervalBlockIterator(interval);
             }
         };
     }
 
-    private static AbstractBlock<?> moveSpillOutOfLoop(AbstractBlock<?> defBlock, AbstractBlock<?> spillBlock) {
+    private static AbstractBlockBase<?> moveSpillOutOfLoop(AbstractBlockBase<?> defBlock, AbstractBlockBase<?> spillBlock) {
         int defLoopDepth = defBlock.getLoopDepth();
-        for (AbstractBlock<?> block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) {
+        for (AbstractBlockBase<?> block = spillBlock.getDominator(); !defBlock.equals(block); block = block.getDominator()) {
             assert block != null : "spill block not dominated by definition block?";
             if (block.getLoopDepth() <= defLoopDepth) {
                 assert block.getLoopDepth() == defLoopDepth : "Cannot spill an interval outside of the loop where it is defined!";
@@ -1970,7 +1977,7 @@
 
                 try (Indent indent2 = Debug.logAndIndent("Basic Blocks")) {
                     for (int i = 0; i < blockCount(); i++) {
-                        AbstractBlock<?> block = blockAt(i);
+                        AbstractBlockBase<?> block = blockAt(i);
                         Debug.log("B%d [%d, %d, %s] ", block.getId(), getFirstLirInstructionId(block), getLastLirInstructionId(block), block.getLoop());
                     }
                 }
@@ -2103,7 +2110,7 @@
             otherIntervals.addRange(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
             IntervalWalker iw = new IntervalWalker(this, fixedIntervals, otherIntervals);
 
-            for (AbstractBlock<?> block : sortedBlocks) {
+            for (AbstractBlockBase<?> block : sortedBlocks) {
                 List<LIRInstruction> instructions = ir.getLIRforBlock(block);
 
                 for (int j = 0; j < instructions.size(); j++) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -27,13 +27,14 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 
-public final class LinearScanPhase extends LIRMidTierPhase {
+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();
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
+        new LinearScan(target, lirGenRes, spillMoveFactory).allocate();
     }
 
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LinearScanWalker.java	Mon Mar 02 19:11:22 2015 +0100
@@ -63,11 +63,11 @@
         return allocator.blockCount();
     }
 
-    AbstractBlock<?> blockAt(int idx) {
+    AbstractBlockBase<?> blockAt(int idx) {
         return allocator.blockAt(idx);
     }
 
-    AbstractBlock<?> blockOfOpWithId(int opId) {
+    AbstractBlockBase<?> blockOfOpWithId(int opId) {
         return allocator.blockForId(opId);
     }
 
@@ -239,7 +239,7 @@
         // optimized away later in assignRegNums
 
         int opId = (operandId + 1) & ~1;
-        AbstractBlock<?> opBlock = allocator.blockForId(opId);
+        AbstractBlockBase<?> opBlock = allocator.blockForId(opId);
         assert opId > 0 && allocator.blockForId(opId - 2) == opBlock : "cannot insert move at block boundary";
 
         // calculate index of instruction inside instruction list of current block
@@ -263,7 +263,7 @@
         moveResolver.addMapping(srcIt, dstIt);
     }
 
-    int findOptimalSplitPos(AbstractBlock<?> minBlock, AbstractBlock<?> maxBlock, int maxSplitPos) {
+    int findOptimalSplitPos(AbstractBlockBase<?> minBlock, AbstractBlockBase<?> maxBlock, int maxSplitPos) {
         int fromBlockNr = minBlock.getLinearScanNumber();
         int toBlockNr = maxBlock.getLinearScanNumber();
 
@@ -280,7 +280,7 @@
 
         int minLoopDepth = maxBlock.getLoopDepth();
         for (int i = toBlockNr - 1; i >= fromBlockNr; i--) {
-            AbstractBlock<?> cur = blockAt(i);
+            AbstractBlockBase<?> cur = blockAt(i);
 
             if (cur.getLoopDepth() < minLoopDepth) {
                 // block with lower loop-depth found . split at the end of this block
@@ -308,13 +308,13 @@
             // beginning of a block, then minSplitPos is also a possible split position.
             // Use the block before as minBlock, because then minBlock.lastLirInstructionId() + 2 ==
             // minSplitPos
-            AbstractBlock<?> minBlock = allocator.blockForId(minSplitPos - 1);
+            AbstractBlockBase<?> minBlock = allocator.blockForId(minSplitPos - 1);
 
             // reason for using maxSplitPos - 1: otherwise there would be an assert on failure
             // when an interval ends at the end of the last block of the method
             // (in this case, maxSplitPos == allocator().maxLirOpId() + 2, and there is no
             // block at this opId)
-            AbstractBlock<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
+            AbstractBlockBase<?> maxBlock = allocator.blockForId(maxSplitPos - 1);
 
             assert minBlock.getLinearScanNumber() <= maxBlock.getLinearScanNumber() : "invalid order";
             if (minBlock == maxBlock) {
@@ -352,7 +352,7 @@
                             // Desired result: uses tagged as shouldHaveRegister inside a loop cause
                             // a reloading
                             // of the interval (normally, only mustHaveRegister causes a reloading)
-                            AbstractBlock<?> loopBlock = allocator.blockForId(loopEndPos);
+                            AbstractBlockBase<?> loopBlock = allocator.blockForId(loopEndPos);
 
                             Debug.log("interval is used in loop that ends in block B%d, so trying to move maxBlock back from B%d to B%d", loopBlock.getId(), maxBlock.getId(), loopBlock.getId());
                             assert loopBlock != minBlock : "loopBlock and minBlock must be different because block boundary is needed between";
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/LocationMarker.java	Mon Mar 02 19:11:22 2015 +0100
@@ -35,6 +35,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.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
@@ -42,7 +43,7 @@
  * Mark all live references for a frame state. The frame state use this information to build the OOP
  * maps.
  */
-public final class LocationMarker extends LIRMidTierPhase {
+public final class LocationMarker extends AllocationPhase {
 
     public static class Options {
         // @formatter:off
@@ -52,7 +53,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
         new Marker(lirGenRes.getLIR(), lirGenRes.getFrameMap()).build();
     }
 
@@ -72,19 +73,19 @@
         }
 
         private void build() {
-            Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+            Deque<AbstractBlockBase<?>> 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()) {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
                 liveInMap.put(block, frameMap.initReferenceMap(true));
             }
             while (!worklist.isEmpty()) {
-                AbstractBlock<?> block = worklist.poll();
+                AbstractBlockBase<?> block = worklist.poll();
                 processBlock(block, worklist);
             }
             // finish states
-            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
                 List<LIRInstruction> instructions = lir.getLIRforBlock(block);
                 for (int i = instructions.size() - 1; i >= 0; i--) {
                     LIRInstruction inst = instructions.get(i);
@@ -97,7 +98,7 @@
         /**
          * Merge outSet with in-set of successors.
          */
-        private boolean updateOutBlock(AbstractBlock<?> block) {
+        private boolean updateOutBlock(AbstractBlockBase<?> block) {
             ReferenceMap union = frameMap.initReferenceMap(true);
             block.getSuccessors().forEach(succ -> union.updateUnion(liveInMap.get(succ)));
             ReferenceMap outSet = liveOutMap.get(block);
@@ -109,7 +110,7 @@
             return false;
         }
 
-        private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
+        private void processBlock(AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) {
             if (updateOutBlock(block)) {
                 try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
                     BlockClosure closure = new BlockClosure(liveOutMap.get(block).clone());
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/MoveResolver.java	Mon Mar 02 19:11:22 2015 +0100
@@ -203,7 +203,7 @@
         AllocatableValue fromOpr = fromInterval.operand;
         AllocatableValue toOpr = toInterval.operand;
 
-        insertionBuffer.append(insertIdx, allocator.ir.getSpillMoveFactory().createMove(toOpr, fromOpr));
+        insertionBuffer.append(insertIdx, allocator.getSpillMoveFactory().createMove(toOpr, fromOpr));
 
         Debug.log("insert move from %s to %s at %d", fromInterval, toInterval, insertIdx);
     }
@@ -213,7 +213,7 @@
         assert insertIdx != -1 : "must setup insert position first";
 
         AllocatableValue toOpr = toInterval.operand;
-        insertionBuffer.append(insertIdx, allocator.ir.getSpillMoveFactory().createMove(toOpr, fromOpr));
+        insertionBuffer.append(insertIdx, allocator.getSpillMoveFactory().createMove(toOpr, fromOpr));
 
         Debug.log("insert move from value %s to %s at %d", fromOpr, toInterval, insertIdx);
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/OptimizingLinearScanWalker.java	Mon Mar 02 19:11:22 2015 +0100
@@ -71,14 +71,14 @@
     @Override
     void walk() {
         try (Scope s = Debug.scope("OptimizingLinearScanWalker")) {
-            for (AbstractBlock<?> block : allocator.sortedBlocks) {
+            for (AbstractBlockBase<?> block : allocator.sortedBlocks) {
                 optimizeBlock(block);
             }
         }
         super.walk();
     }
 
-    private void optimizeBlock(AbstractBlock<?> block) {
+    private void optimizeBlock(AbstractBlockBase<?> block) {
         if (block.getPredecessorCount() == 1) {
             int nextBlock = allocator.getFirstLirInstructionId(block);
             try (Scope s1 = Debug.scope("LSRAOptimization")) {
@@ -114,7 +114,7 @@
         }
     }
 
-    private boolean optimize(int currentPos, AbstractBlock<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
+    private boolean optimize(int currentPos, AbstractBlockBase<?> currentBlock, Interval currentInterval, RegisterBinding binding) {
         // BEGIN initialize and sanity checks
         assert currentBlock != null : "block must not be null";
         assert currentInterval != null : "interval must not be null";
@@ -136,7 +136,7 @@
         assert currentLocation != null : "active intervals must have a location assigned!";
 
         // get predecessor stuff
-        AbstractBlock<?> predecessorBlock = currentBlock.getPredecessors().get(0);
+        AbstractBlockBase<?> predecessorBlock = currentBlock.getPredecessors().get(0);
         int predEndId = allocator.getLastLirInstructionId(predecessorBlock);
         Interval predecessorInterval = currentInterval.getIntervalCoveringOpId(predEndId);
         assert predecessorInterval != null : "variable not live at the end of the only predecessor! " + predecessorBlock + " -> " + currentBlock + " interval: " + currentInterval;
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Range.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/Range.java	Mon Mar 02 19:11:22 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/alloc/lsra/RegisterVerifier.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/alloc/lsra/RegisterVerifier.java	Mon Mar 02 19:11:22 2015 +0100
@@ -41,7 +41,7 @@
 final class RegisterVerifier {
 
     LinearScan allocator;
-    List<AbstractBlock<?>> workList; // all blocks that must be processed
+    List<AbstractBlockBase<?>> workList; // all blocks that must be processed
     ArrayMap<Interval[]> savedStates; // saved information of previous check
 
     // simplified access to methods of LinearScan
@@ -55,15 +55,15 @@
     }
 
     // accessors
-    Interval[] stateForBlock(AbstractBlock<?> block) {
+    Interval[] stateForBlock(AbstractBlockBase<?> block) {
         return savedStates.get(block.getId());
     }
 
-    void setStateForBlock(AbstractBlock<?> block, Interval[] savedState) {
+    void setStateForBlock(AbstractBlockBase<?> block, Interval[] savedState) {
         savedStates.put(block.getId(), savedState);
     }
 
-    void addToWorkList(AbstractBlock<?> block) {
+    void addToWorkList(AbstractBlockBase<?> block) {
         if (!workList.contains(block)) {
             workList.add(block);
         }
@@ -76,7 +76,7 @@
 
     }
 
-    void verify(AbstractBlock<?> start) {
+    void verify(AbstractBlockBase<?> start) {
         // setup input registers (method arguments) for first block
         Interval[] inputState = new Interval[stateSize()];
         setStateForBlock(start, inputState);
@@ -84,14 +84,14 @@
 
         // main loop for verification
         do {
-            AbstractBlock<?> block = workList.get(0);
+            AbstractBlockBase<?> block = workList.get(0);
             workList.remove(0);
 
             processBlock(block);
         } while (!workList.isEmpty());
     }
 
-    private void processBlock(AbstractBlock<?> block) {
+    private void processBlock(AbstractBlockBase<?> block) {
         try (Indent indent = Debug.logAndIndent("processBlock B%d", block.getId())) {
             // must copy state because it is modified
             Interval[] inputState = copy(stateForBlock(block));
@@ -110,13 +110,13 @@
             processOperations(allocator.ir.getLIRforBlock(block), inputState);
 
             // iterate all successors
-            for (AbstractBlock<?> succ : block.getSuccessors()) {
+            for (AbstractBlockBase<?> succ : block.getSuccessors()) {
                 processSuccessor(succ, inputState);
             }
         }
     }
 
-    private void processSuccessor(AbstractBlock<?> block, Interval[] inputState) {
+    private void processSuccessor(AbstractBlockBase<?> block, Interval[] inputState) {
         Interval[] savedState = stateForBlock(block);
 
         if (savedState != null) {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/CompilationResultBuilder.java	Mon Mar 02 19:11:22 2015 +0100
@@ -330,7 +330,7 @@
      */
     public boolean isSuccessorEdge(LabelRef edge) {
         assert lir != null;
-        List<? extends AbstractBlock<?>> order = lir.codeEmittingOrder();
+        List<? extends AbstractBlockBase<?>> order = lir.codeEmittingOrder();
         assert order.get(currentBlockIndex) == edge.getSourceBlock();
         return currentBlockIndex < order.size() - 1 && order.get(currentBlockIndex + 1) == edge.getTargetBlock();
     }
@@ -344,7 +344,7 @@
         this.lir = lir;
         this.currentBlockIndex = 0;
         frameContext.enter(this);
-        for (AbstractBlock<?> b : lir.codeEmittingOrder()) {
+        for (AbstractBlockBase<?> b : lir.codeEmittingOrder()) {
             emitBlock(b);
             currentBlockIndex++;
         }
@@ -352,7 +352,7 @@
         this.currentBlockIndex = 0;
     }
 
-    private void emitBlock(AbstractBlock<?> block) {
+    private void emitBlock(AbstractBlockBase<?> block) {
         if (Debug.isDumpEnabled()) {
             blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantLoadOptimization.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,6 +24,7 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 import static com.oracle.graal.lir.LIRValueUtil.*;
+import static com.oracle.graal.lir.phases.LIRPhase.Options.*;
 
 import java.util.*;
 
@@ -47,17 +48,17 @@
  * a constant, which is potentially scheduled into a block with high probability, with one or more
  * definitions in blocks with a lower probability.
  */
-public final class ConstantLoadOptimization extends LIRHighTierPhase {
+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> LIROptConstantLoadOptimization = new OptionValue<>(true);
+        public static final NestedBooleanOptionValue LIROptConstantLoadOptimization = new NestedBooleanOptionValue(LIROptimization, true);
         // @formatter:on
     }
 
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen) {
         new Optimization(lirGenRes.getLIR(), lirGen).apply();
     }
 
@@ -135,7 +136,7 @@
                     assert !operand.equals(var) : "constant usage through variable in frame state " + var;
                 }
             };
-            for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
                 for (LIRInstruction inst : lir.getLIRforBlock(block)) {
                     // set instruction id to the index in the lir instruction list
                     inst.visitEachState(stateConsumer);
@@ -152,7 +153,7 @@
         }
 
         private void addUsageToBlockMap(UseEntry entry) {
-            AbstractBlock<?> block = entry.getBlock();
+            AbstractBlockBase<?> block = entry.getBlock();
             List<UseEntry> list = blockMap.get(block);
             if (list == null) {
                 list = new ArrayList<>();
@@ -164,7 +165,7 @@
         /**
          * Collects def-use information for a {@code block}.
          */
-        private void analyzeBlock(AbstractBlock<?> block) {
+        private void analyzeBlock(AbstractBlockBase<?> block) {
             try (Indent indent = Debug.logAndIndent("Block: %s", block)) {
 
                 InstructionValueConsumer loadConsumer = (instruction, value, mode, flags) -> {
@@ -195,14 +196,13 @@
                     }
                 };
 
-                ValuePositionProcedure useProcedure = (instruction, position) -> {
-                    Value value = position.get(instruction);
+                InstructionValueConsumer useConsumer = (instruction, value, mode, flags) -> {
                     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);
+                                tree.addUsage(block, instruction, value);
                                 Debug.log("usage of %s : %s", var, instruction);
                             }
                         }
@@ -214,8 +214,8 @@
                     // set instruction id to the index in the lir instruction list
                     inst.setId(opId++);
                     inst.visitEachOutput(loadConsumer);
-                    inst.forEachInputPos(useProcedure);
-                    inst.forEachAlivePos(useProcedure);
+                    inst.forEachInput(useConsumer);
+                    inst.forEachAlive(useConsumer);
 
                 }
             }
@@ -267,17 +267,17 @@
             Debug.dump(constTree, "ConstantTree for " + tree.getVariable());
         }
 
-        private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlock<?> startBlock) {
-            Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+        private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlockBase<?> startBlock) {
+            Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
             worklist.add(startBlock);
             while (!worklist.isEmpty()) {
-                AbstractBlock<?> block = worklist.pollLast();
+                AbstractBlockBase<?> 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()) {
+                    for (AbstractBlockBase<?> dominated : block.getDominated()) {
                         if (constTree.isMarked(dominated)) {
                             worklist.addLast(dominated);
                         }
@@ -286,18 +286,18 @@
             }
         }
 
-        private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlock<?> block, List<UseEntry> usages) {
+        private void insertLoad(JavaConstant constant, LIRKind kind, AbstractBlockBase<?> 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);
+            LIRInstruction move = lirGen.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);
+                u.setValue(variable);
                 Debug.log("patched instruction %s", u.getInstruction());
             }
         }
@@ -306,7 +306,7 @@
          * Inserts the constant loads created in {@link #createConstantTree} and deletes the
          * original definition.
          */
-        private void rewriteBlock(AbstractBlock<?> block) {
+        private void rewriteBlock(AbstractBlockBase<?> block) {
             // insert moves
             LIRInsertionBuffer buffer = insertionBuffers.get(block);
             if (buffer != null) {
@@ -331,13 +331,13 @@
         }
 
         private void deleteInstruction(DefUseTree tree) {
-            AbstractBlock<?> block = tree.getBlock();
+            AbstractBlockBase<?> 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) {
+        private LIRInsertionBuffer getInsertionBuffer(AbstractBlockBase<?> block) {
             LIRInsertionBuffer insertionBuffer = insertionBuffers.get(block);
             if (insertionBuffer == null) {
                 insertionBuffer = new LIRInsertionBuffer();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTree.java	Mon Mar 02 19:11:22 2015 +0100
@@ -99,7 +99,7 @@
         tree.forEach(u -> getOrInitList(u.getBlock()).add(u));
     }
 
-    private List<UseEntry> getOrInitList(AbstractBlock<?> block) {
+    private List<UseEntry> getOrInitList(AbstractBlockBase<?> block) {
         List<UseEntry> list = blockMap.get(block);
         if (list == null) {
             list = new ArrayList<>();
@@ -108,7 +108,7 @@
         return list;
     }
 
-    public List<UseEntry> getUsages(AbstractBlock<?> block) {
+    public List<UseEntry> getUsages(AbstractBlockBase<?> block) {
         List<UseEntry> list = blockMap.get(block);
         if (list == null) {
             return Collections.emptyList();
@@ -120,7 +120,7 @@
      * Returns the cost object associated with {@code block}. If there is none, a new cost object is
      * created.
      */
-    NodeCost getOrInitCost(AbstractBlock<?> block) {
+    NodeCost getOrInitCost(AbstractBlockBase<?> block) {
         NodeCost cost = getCost(block);
         if (cost == null) {
             cost = new NodeCost(block.probability(), blockMap.get(block), 1);
@@ -145,7 +145,7 @@
     }
 
     @Override
-    public void forEachPropertyPair(AbstractBlock<?> block, BiConsumer<String, String> action) {
+    public void forEachPropertyPair(AbstractBlockBase<?> block, BiConsumer<String, String> action) {
         if (get(Flags.SUBTREE, block) && (block.getDominator() == null || !get(Flags.SUBTREE, block.getDominator()))) {
             action.accept("hasDefinition", "true");
         }
@@ -156,7 +156,7 @@
         return stream(Flags.SUBTREE).count();
     }
 
-    public AbstractBlock<?> getStartBlock() {
+    public AbstractBlockBase<?> getStartBlock() {
         return stream(Flags.SUBTREE).findFirst().get();
     }
 
@@ -164,15 +164,15 @@
         stream(Flags.USAGE).forEach(block -> setDominatorPath(Flags.SUBTREE, block));
     }
 
-    public boolean isMarked(AbstractBlock<?> block) {
+    public boolean isMarked(AbstractBlockBase<?> block) {
         return get(Flags.SUBTREE, block);
     }
 
-    public boolean isLeafBlock(AbstractBlock<?> block) {
+    public boolean isLeafBlock(AbstractBlockBase<?> block) {
         return block.getDominated().stream().noneMatch(this::isMarked);
     }
 
-    public void setSolution(AbstractBlock<?> block) {
+    public void setSolution(AbstractBlockBase<?> block) {
         set(Flags.MATERIALIZE, block);
     }
 
@@ -180,7 +180,7 @@
         return getBlocks().size();
     }
 
-    public void traverseTreeWhileTrue(AbstractBlock<?> block, Predicate<AbstractBlock<?>> action) {
+    public void traverseTreeWhileTrue(AbstractBlockBase<?> block, Predicate<AbstractBlockBase<?>> action) {
         assert block != null : "block must not be null!";
         if (action.test(block)) {
             block.getDominated().stream().filter(this::isMarked).forEach(dominated -> traverseTreeWhileTrue(dominated, action));
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTreeAnalyzer.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/ConstantTreeAnalyzer.java	Mon Mar 02 19:11:22 2015 +0100
@@ -37,7 +37,7 @@
     private final ConstantTree tree;
     private final BitSet visited;
 
-    public static NodeCost analyze(ConstantTree tree, AbstractBlock<?> startBlock) {
+    public static NodeCost analyze(ConstantTree tree, AbstractBlockBase<?> startBlock) {
         try (Scope s = Debug.scope("ConstantTreeAnalyzer")) {
             ConstantTreeAnalyzer analyzer = new ConstantTreeAnalyzer(tree);
             analyzer.analyzeBlocks(startBlock);
@@ -60,11 +60,11 @@
      *
      * @param startBlock The start block of the dominator subtree.
      */
-    private void analyzeBlocks(AbstractBlock<?> startBlock) {
-        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+    private void analyzeBlocks(AbstractBlockBase<?> startBlock) {
+        Deque<AbstractBlockBase<?>> worklist = new ArrayDeque<>();
         worklist.offerLast(startBlock);
         while (!worklist.isEmpty()) {
-            AbstractBlock<?> block = worklist.pollLast();
+            AbstractBlockBase<?> block = worklist.pollLast();
             try (Indent i = Debug.logAndIndent(3, "analyze: %s", block)) {
                 assert block != null : "worklist is empty!";
                 assert isMarked(block) : "Block not part of the dominator tree: " + block;
@@ -79,7 +79,7 @@
                     // if not yet visited (and not a leaf block) process all children first!
                     Debug.log(3, "not marked");
                     worklist.offerLast(block);
-                    List<? extends AbstractBlock<?>> children = block.getDominated();
+                    List<? extends AbstractBlockBase<?>> children = block.getDominated();
                     children.forEach(child -> filteredPush(worklist, child));
                     visited.set(block.getId());
                 } else {
@@ -97,15 +97,15 @@
      *
      * @param block The block to be processed.
      */
-    private void process(AbstractBlock<?> block) {
+    private void process(AbstractBlockBase<?> block) {
         List<UseEntry> usages = new ArrayList<>();
         double bestCost = 0;
         int numMat = 0;
-        List<? extends AbstractBlock<?>> children = block.getDominated();
+        List<? extends AbstractBlockBase<?>> children = block.getDominated();
         assert children.stream().anyMatch(this::isMarked) : "no children? should have called leafCost(): " + block;
 
         // collect children costs
-        for (AbstractBlock<?> child : children) {
+        for (AbstractBlockBase<?> child : children) {
             if (isMarked(child)) {
                 NodeCost childCost = tree.getCost(child);
                 assert childCost != null : "Child with null cost? block: " + child;
@@ -151,23 +151,23 @@
         return probabilityBlock * Math.pow(0.9, numMat - 1) < probabilityChildren;
     }
 
-    private void filteredPush(Deque<AbstractBlock<?>> worklist, AbstractBlock<?> block) {
+    private void filteredPush(Deque<AbstractBlockBase<?>> worklist, AbstractBlockBase<?> block) {
         if (isMarked(block)) {
             Debug.log(3, "adding %s to the worklist", block);
             worklist.offerLast(block);
         }
     }
 
-    private void leafCost(AbstractBlock<?> block) {
+    private void leafCost(AbstractBlockBase<?> block) {
         tree.set(Flags.CANDIDATE, block);
         tree.getOrInitCost(block);
     }
 
-    private boolean isMarked(AbstractBlock<?> block) {
+    private boolean isMarked(AbstractBlockBase<?> block) {
         return tree.isMarked(block);
     }
 
-    private boolean isLeafBlock(AbstractBlock<?> block) {
+    private boolean isLeafBlock(AbstractBlockBase<?> block) {
         return tree.isLeafBlock(block);
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/DefUseTree.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/DefUseTree.java	Mon Mar 02 19:11:22 2015 +0100
@@ -35,10 +35,10 @@
  */
 class DefUseTree {
     private final LIRInstruction instruction;
-    private final AbstractBlock<?> block;
+    private final AbstractBlockBase<?> block;
     private final List<UseEntry> uses;
 
-    public DefUseTree(LIRInstruction instruction, AbstractBlock<?> block) {
+    public DefUseTree(LIRInstruction instruction, AbstractBlockBase<?> block) {
         assert instruction instanceof MoveOp : "Not a MoveOp: " + instruction;
         this.instruction = instruction;
         this.block = block;
@@ -57,7 +57,7 @@
         return instruction;
     }
 
-    public AbstractBlock<?> getBlock() {
+    public AbstractBlockBase<?> getBlock() {
         return block;
     }
 
@@ -66,8 +66,8 @@
         return "DefUseTree [" + instruction + "|" + block + "," + uses + "]";
     }
 
-    public void addUsage(AbstractBlock<?> b, LIRInstruction inst, ValuePosition position) {
-        uses.add(new UseEntry(b, inst, position));
+    public void addUsage(AbstractBlockBase<?> b, LIRInstruction inst, Value value) {
+        uses.add(new UseEntry(b, inst, value));
     }
 
     public int usageCount() {
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/UseEntry.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/constopt/UseEntry.java	Mon Mar 02 19:11:22 2015 +0100
@@ -31,34 +31,44 @@
  */
 class UseEntry {
 
-    private final AbstractBlock<?> block;
+    private final AbstractBlockBase<?> block;
     private final LIRInstruction instruction;
-    private final ValuePosition position;
+    private final Value value;
 
-    public UseEntry(AbstractBlock<?> block, LIRInstruction instruction, ValuePosition position) {
+    public UseEntry(AbstractBlockBase<?> block, LIRInstruction instruction, Value value) {
         this.block = block;
         this.instruction = instruction;
-        this.position = position;
+        this.value = value;
     }
 
     public LIRInstruction getInstruction() {
         return instruction;
     }
 
-    public AbstractBlock<?> getBlock() {
+    public AbstractBlockBase<?> getBlock() {
         return block;
     }
 
-    public ValuePosition getPosition() {
-        return position;
+    public void setValue(Value newValue) {
+        replaceValue(instruction, value, newValue);
+    }
+
+    private static void replaceValue(LIRInstruction op, Value oldValue, Value newValue) {
+        ValueProcedure proc = (value, mode, flags) -> value.identityEquals(oldValue) ? newValue : value;
+        op.forEachAlive(proc);
+        op.forEachInput(proc);
+        op.forEachOutput(proc);
+        op.forEachTemp(proc);
+        op.forEachState(proc);
     }
 
     public Value getValue() {
-        return position.get(instruction);
+        return value;
     }
 
     @Override
     public String toString() {
         return "Use[" + getValue() + ":" + instruction + ":" + block + "]";
     }
+
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/framemap/FrameMapBuilderImpl.java	Mon Mar 02 19:11:22 2015 +0100
@@ -117,7 +117,7 @@
         InstructionValueConsumer verifySlots = (LIRInstruction op, Value value, OperandMode mode, EnumSet<OperandFlag> flags) -> {
             assert !isVirtualStackSlot(value) : String.format("Instruction %s contains a virtual stack slot %s", op, value);
         };
-        for (AbstractBlock<?> block : lir.getControlFlowGraph().getBlocks()) {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
             lir.getLIRforBlock(block).forEach(op -> {
                 op.visitEachInput(verifySlots);
                 op.visitEachAlive(verifySlots);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -60,7 +60,7 @@
     private final CodeGenProviders providers;
     private final CallingConvention cc;
 
-    private AbstractBlock<?> currentBlock;
+    private AbstractBlockBase<?> currentBlock;
 
     private LIRGenerationResult res;
 
@@ -186,7 +186,7 @@
         res.getLIR().getLIRforBlock(currentBlock).add(op);
     }
 
-    public boolean hasBlockEnd(AbstractBlock<?> block) {
+    public boolean hasBlockEnd(AbstractBlockBase<?> block) {
         List<LIRInstruction> ops = getResult().getLIR().getLIRforBlock(block);
         if (ops.size() == 0) {
             return false;
@@ -194,7 +194,7 @@
         return ops.get(ops.size() - 1) instanceof BlockEndOp;
     }
 
-    public final void doBlockStart(AbstractBlock<?> block) {
+    public final void doBlockStart(AbstractBlockBase<?> block) {
         if (Options.PrintIRWithLIR.getValue()) {
             TTY.print(block.toString());
         }
@@ -212,7 +212,7 @@
         }
     }
 
-    public final void doBlockEnd(AbstractBlock<?> block) {
+    public final void doBlockEnd(AbstractBlockBase<?> block) {
 
         if (Options.TraceLIRGeneratorLevel.getValue() >= 1) {
             TTY.println("END Generating LIR for block B" + block.getId());
@@ -226,7 +226,7 @@
     }
 
     public void emitIncomingValues(Value[] params) {
-        ((LabelOp) res.getLIR().getLIRforBlock(currentBlock).get(0)).setIncomingValues(params);
+        ((LabelOp) res.getLIR().getLIRforBlock(getCurrentBlock()).get(0)).setIncomingValues(params);
     }
 
     public abstract void emitJump(LabelRef label);
@@ -379,14 +379,10 @@
         }
     }
 
-    public AbstractBlock<?> getCurrentBlock() {
+    public AbstractBlockBase<?> getCurrentBlock() {
         return currentBlock;
     }
 
-    void setCurrentBlock(AbstractBlock<?> block) {
-        currentBlock = block;
-    }
-
     public LIRGenerationResult getResult() {
         return res;
     }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGeneratorTool.java	Mon Mar 02 19:11:22 2015 +0100
@@ -32,6 +32,11 @@
 
 public interface LIRGeneratorTool extends ArithmeticLIRGenerator {
 
+    public interface SpillMoveFactory {
+
+        LIRInstruction createMove(AllocatableValue result, Value input);
+    }
+
     CodeGenProviders getProviders();
 
     TargetDescription target();
@@ -42,15 +47,17 @@
 
     ForeignCallsProvider getForeignCalls();
 
-    AbstractBlock<?> getCurrentBlock();
+    AbstractBlockBase<?> getCurrentBlock();
 
     LIRGenerationResult getResult();
 
-    boolean hasBlockEnd(AbstractBlock<?> block);
+    boolean hasBlockEnd(AbstractBlockBase<?> block);
+
+    SpillMoveFactory getSpillMoveFactory();
 
-    void doBlockStart(AbstractBlock<?> block);
+    void doBlockStart(AbstractBlockBase<?> block);
 
-    void doBlockEnd(AbstractBlock<?> block);
+    void doBlockEnd(AbstractBlockBase<?> block);
 
     Value emitLoadConstant(LIRKind kind, Constant constant);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationPhase.java	Mon Mar 02 19:11:22 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.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.*;
+
+public abstract class AllocationPhase extends LIRPhase<AllocationPhase.AllocationContext> {
+
+    public static final class AllocationContext {
+        private final SpillMoveFactory spillMoveFactory;
+
+        public AllocationContext(SpillMoveFactory spillMoveFactory) {
+            this.spillMoveFactory = spillMoveFactory;
+        }
+    }
+
+    @Override
+    protected final <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, AllocationContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.spillMoveFactory);
+    }
+
+    protected abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    SpillMoveFactory spillMoveFactory);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/AllocationStage.java	Mon Mar 02 19:11:22 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());
+    }
+}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRHighTier.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.phases;
-
-import com.oracle.graal.lir.constopt.*;
-import com.oracle.graal.lir.phases.LIRHighTierPhase.*;
-
-public class LIRHighTier extends LIRPhaseSuite<LIRHighTierContext> {
-    public LIRHighTier() {
-        if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue()) {
-            appendPhase(new ConstantLoadOptimization());
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRHighTierPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LIRHighTierPhase extends LIRPhase<LIRHighTierPhase.LIRHighTierContext> {
-
-    public static final class LIRHighTierContext {
-        private final LIRGeneratorTool lirGen;
-
-        public LIRHighTierContext(LIRGeneratorTool lirGen) {
-            this.lirGen = lirGen;
-        }
-
-    }
-
-    @Override
-    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRHighTierContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder, context.lirGen);
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRGeneratorTool lirGen);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRLowTier.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.phases;
-
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.phases.LIRLowTierPhase.*;
-import com.oracle.graal.options.*;
-
-public class LIRLowTier extends LIRPhaseSuite<LIRLowTierContext> {
-    public static class Options {
-        // @formatter:off
-        @Option(help = "", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LIROptEdgeMoveOptimizer = new OptionValue<>(true);
-        @Option(help = "", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LIROptControlFlowOptmizer = new OptionValue<>(true);
-        @Option(help = "", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LIROptRedundantMoveElimination = new OptionValue<>(true);
-        @Option(help = "", type = OptionType.Debug)
-        public static final OptionValue<Boolean> LIROptNullCheckOptimizer = new OptionValue<>(true);
-        // @formatter:on
-    }
-
-    public LIRLowTier() {
-        if (Options.LIROptEdgeMoveOptimizer.getValue()) {
-            appendPhase(new EdgeMoveOptimizer());
-        }
-        if (Options.LIROptControlFlowOptmizer.getValue()) {
-            appendPhase(new ControlFlowOptimizer());
-        }
-        if (Options.LIROptRedundantMoveElimination.getValue()) {
-            appendPhase(new RedundantMoveElimination());
-        }
-        if (Options.LIROptNullCheckOptimizer.getValue()) {
-            appendPhase(new NullCheckOptimizer());
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRLowTierPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LIRLowTierPhase extends LIRPhase<LIRLowTierPhase.LIRLowTierContext> {
-
-    public static final class LIRLowTierContext {
-    }
-
-    @Override
-    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRLowTierContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRMidTier.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.phases;
-
-import com.oracle.graal.lir.alloc.lsra.*;
-import com.oracle.graal.lir.phases.LIRMidTierPhase.*;
-import com.oracle.graal.lir.stackslotalloc.*;
-
-public class LIRMidTier extends LIRPhaseSuite<LIRMidTierContext> {
-    public LIRMidTier() {
-        appendPhase(new LinearScanPhase());
-
-        // build frame map
-        if (LSStackSlotAllocator.Options.LIROptLSStackSlotAllocator.getValue()) {
-            appendPhase(new LSStackSlotAllocator());
-        } else {
-            appendPhase(new SimpleStackSlotAllocator());
-        }
-        // currently we mark locations only if we do register allocation
-        appendPhase(new LocationMarker());
-    }
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRMidTierPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.lir.phases;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.lir.gen.*;
-
-public abstract class LIRMidTierPhase extends LIRPhase<LIRMidTierPhase.LIRMidTierContext> {
-
-    public static final class LIRMidTierContext {
-    }
-
-    @Override
-    protected final <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, LIRMidTierContext context) {
-        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
-    }
-
-    protected abstract <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder);
-
-}
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.debug.internal.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.options.*;
 
 /**
  * Base class for all {@link LIR low-level} phases. Subclasses should be stateless. There will be
@@ -40,6 +41,13 @@
  */
 public abstract class LIRPhase<C> {
 
+    public static class Options {
+        // @formatter:off
+        @Option(help = "Enable LIR level optimiztations.", type = OptionType.Debug)
+        public static final OptionValue<Boolean> LIROptimization = new OptionValue<>(true);
+        // @formatter:on
+    }
+
     private static final int PHASE_DUMP_LEVEL = 2;
 
     private CharSequence name;
@@ -73,22 +81,24 @@
         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) {
+    public final <B extends AbstractBlockBase<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());
+    public final <B extends AbstractBlockBase<B>> void apply(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context, boolean dumpLIR) {
+        try (Scope s = Debug.scope(getName(), this)) {
+            try (TimerCloseable a = timer.start(); 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 abstract <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context);
 
     protected CharSequence createName() {
         String className = LIRPhase.this.getClass().getName();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhaseSuite.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRPhaseSuite.java	Mon Mar 02 19:11:22 2015 +0100
@@ -69,7 +69,7 @@
     }
 
     @Override
-    protected <B extends AbstractBlock<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, C context) {
+    protected <B extends AbstractBlockBase<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);
         }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRSuites.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/phases/LIRSuites.java	Mon Mar 02 19:11:22 2015 +0100
@@ -25,54 +25,54 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.lir.phases.LIRHighTierPhase.LIRHighTierContext;
-import com.oracle.graal.lir.phases.LIRLowTierPhase.LIRLowTierContext;
-import com.oracle.graal.lir.phases.LIRMidTierPhase.LIRMidTierContext;
+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<LIRHighTierContext> highTier;
-    private final LIRPhaseSuite<LIRMidTierContext> midTier;
-    private final LIRPhaseSuite<LIRLowTierContext> lowTier;
+    private final LIRPhaseSuite<PreAllocationOptimizationContext> preAllocOptStage;
+    private final LIRPhaseSuite<AllocationContext> allocStage;
+    private final LIRPhaseSuite<PostAllocationOptimizationContext> postAllocStage;
 
-    public LIRSuites(LIRPhaseSuite<LIRHighTierContext> highTier, LIRPhaseSuite<LIRMidTierContext> midTier, LIRPhaseSuite<LIRLowTierContext> lowTier) {
-        this.highTier = highTier;
-        this.midTier = midTier;
-        this.lowTier = lowTier;
+    public LIRSuites(LIRPhaseSuite<PreAllocationOptimizationContext> preAllocOptStage, LIRPhaseSuite<AllocationContext> allocStage, LIRPhaseSuite<PostAllocationOptimizationContext> postAllocStage) {
+        this.preAllocOptStage = preAllocOptStage;
+        this.allocStage = allocStage;
+        this.postAllocStage = postAllocStage;
     }
 
     /**
-     * {@link LIRHighTierPhase}s are executed between {@link LIR} generation and register
-     * allocation.
+     * {@link PreAllocationOptimizationPhase}s are executed between {@link LIR} generation and
+     * register allocation.
      * <p>
-     * {@link LIRHighTierPhase Implementers} can create new {@link LIRGeneratorTool#newVariable
-     * variables}, {@link LIRGenerationResult#getFrameMap stack slots} and
-     * {@link LIRGenerationResult#getFrameMapBuilder virtual stack slots}.
+     * {@link PreAllocationOptimizationPhase Implementers} can create new
+     * {@link LIRGeneratorTool#newVariable variables}, {@link LIRGenerationResult#getFrameMap stack
+     * slots} and {@link LIRGenerationResult#getFrameMapBuilder virtual stack slots}.
      */
-    public LIRPhaseSuite<LIRHighTierContext> getHighTier() {
-        return highTier;
+    public LIRPhaseSuite<PreAllocationOptimizationContext> getPreAllocationOptimizationStage() {
+        return preAllocOptStage;
     }
 
     /**
-     * {@link LIRMidTierPhase}s are responsible for register allocation and translating
+     * {@link AllocationPhase}s are responsible for register allocation and translating
      * {@link VirtualStackSlot}s into {@link StackSlot}s.
      * <p>
-     * After the {@link LIRMidTier} there should be no more {@link Variable}s and
+     * After the {@link AllocationStage} there should be no more {@link Variable}s and
      * {@link VirtualStackSlot}s.
      */
-    public LIRPhaseSuite<LIRMidTierContext> getMidTier() {
-        return midTier;
+    public LIRPhaseSuite<AllocationContext> getAllocationStage() {
+        return allocStage;
     }
 
     /**
-     * {@link LIRLowTierPhase}s are executed after register allocation and before machine code
-     * generation.
+     * {@link PostAllocationOptimizationPhase}s are executed after register allocation and before
+     * machine code generation.
      * <p>
-     * A {@link LIRLowTierPhase} must not introduce new {@link Variable}s, {@link VirtualStackSlot}s
-     * or {@link StackSlot}s.
+     * A {@link PostAllocationOptimizationPhase} must not introduce new {@link Variable}s,
+     * {@link VirtualStackSlot}s or {@link StackSlot}s.
      */
-    public LIRPhaseSuite<LIRLowTierContext> getLowTier() {
-        return lowTier;
+    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	Mon Mar 02 19:11:22 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 AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    PostAllocationOptimizationContext context) {
+        run(target, lirGenRes, codeEmittingOrder, linearScanOrder);
+    }
+
+    protected abstract <B extends AbstractBlockBase<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	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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 static com.oracle.graal.lir.phases.LIRPhase.Options.*;
+
+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 NestedBooleanOptionValue LIROptEdgeMoveOptimizer = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptControlFlowOptmizer = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptRedundantMoveElimination = new NestedBooleanOptionValue(LIROptimization, true);
+        @Option(help = "", type = OptionType.Debug)
+        public static final NestedBooleanOptionValue LIROptNullCheckOptimizer = new NestedBooleanOptionValue(LIROptimization, 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	Mon Mar 02 19:11:22 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 AbstractBlockBase<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 AbstractBlockBase<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	Mon Mar 02 19:11:22 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/FixPointIntervalBuilder.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/FixPointIntervalBuilder.java	Mon Mar 02 19:11:22 2015 +0100
@@ -65,15 +65,15 @@
      * virtual stack slots.
      */
     Set<LIRInstruction> build() {
-        Deque<AbstractBlock<?>> worklist = new ArrayDeque<>();
+        Deque<AbstractBlockBase<?>> 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()) {
+        for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
             liveInMap.put(block, new BitSet(stackSlotMap.length));
         }
         while (!worklist.isEmpty()) {
-            AbstractBlock<?> block = worklist.poll();
+            AbstractBlockBase<?> block = worklist.poll();
             processBlock(block, worklist);
         }
         return usePos;
@@ -82,7 +82,7 @@
     /**
      * Merge outSet with in-set of successors.
      */
-    private boolean updateOutBlock(AbstractBlock<?> block) {
+    private boolean updateOutBlock(AbstractBlockBase<?> block) {
         BitSet union = new BitSet(stackSlotMap.length);
         block.getSuccessors().forEach(succ -> union.or(liveInMap.get(succ)));
         BitSet outSet = liveOutMap.get(block);
@@ -94,7 +94,7 @@
         return false;
     }
 
-    private void processBlock(AbstractBlock<?> block, Deque<AbstractBlock<?>> worklist) {
+    private void processBlock(AbstractBlockBase<?> block, Deque<AbstractBlockBase<?>> worklist) {
         if (updateOutBlock(block)) {
             try (Indent indent = Debug.logAndIndent("handle block %s", block)) {
                 List<LIRInstruction> instructions = lir.getLIRforBlock(block);
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/LSStackSlotAllocator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.lir.stackslotalloc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.phases.LIRPhase.Options.LIROptimization;
 
 import java.util.*;
 import java.util.function.*;
@@ -38,6 +39,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.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.options.*;
 
@@ -51,12 +53,12 @@
  * {@link OperandFlag#UNINITIALIZED}. Otherwise the stack slot might be reused and its content
  * destroyed.
  */
-public final class LSStackSlotAllocator extends LIRMidTierPhase 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> LIROptLSStackSlotAllocator = new OptionValue<>(true);
+        public static final NestedBooleanOptionValue LIROptLSStackSlotAllocator = new NestedBooleanOptionValue(LIROptimization, true);
         // @formatter:on
     }
 
@@ -68,7 +70,7 @@
     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) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
         lirGenRes.buildFrameMap(this);
     }
 
@@ -84,7 +86,7 @@
         private final StackInterval[] stackSlotMap;
         private final PriorityQueue<StackInterval> unhandled;
         private final PriorityQueue<StackInterval> active;
-        private final List<? extends AbstractBlock<?>> sortedBlocks;
+        private final List<? extends AbstractBlockBase<?>> sortedBlocks;
         private final int maxOpId;
 
         private Allocator(LIR lir, FrameMapBuilderTool frameMapBuilder) {
@@ -149,10 +151,10 @@
          *
          * @return The id of the last operation.
          */
-        private static int numberInstructions(LIR lir, List<? extends AbstractBlock<?>> sortedBlocks) {
+        private static int numberInstructions(LIR lir, List<? extends AbstractBlockBase<?>> sortedBlocks) {
             int opId = 0;
             int index = 0;
-            for (AbstractBlock<?> block : sortedBlocks) {
+            for (AbstractBlockBase<?> block : sortedBlocks) {
 
                 List<LIRInstruction> instructions = lir.getLIRforBlock(block);
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/stackslotalloc/SimpleStackSlotAllocator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -34,12 +34,13 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.gen.LIRGeneratorTool.SpillMoveFactory;
 import com.oracle.graal.lir.phases.*;
 
-public class SimpleStackSlotAllocator extends LIRMidTierPhase 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) {
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder, SpillMoveFactory spillMoveFactory) {
         lirGenRes.buildFrameMap(this);
     }
 
@@ -75,7 +76,7 @@
                 }
                 return value;
             };
-            for (AbstractBlock<?> block : res.getLIR().getControlFlowGraph().getBlocks()) {
+            for (AbstractBlockBase<?> block : res.getLIR().getControlFlowGraph().getBlocks()) {
                 try (Indent indent0 = Debug.logAndIndent("block: %s", block)) {
                     for (LIRInstruction inst : res.getLIR().getLIRforBlock(block)) {
                         try (Indent indent1 = Debug.logAndIndent("Inst: %d: %s", inst.id(), inst)) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Mon Mar 02 19:11:22 2015 +0100
@@ -175,13 +175,13 @@
                 negated = true;
             }
             LogicNode ifTest = ifNode.condition();
-            if (!(ifTest instanceof IntegerLessThanNode)) {
+            if (!(ifTest instanceof IntegerLessThanNode) && !(ifTest instanceof IntegerEqualsNode)) {
                 if (ifTest instanceof IntegerBelowNode) {
                     Debug.log("Ignored potential Counted loop at %s with |<|", loopBegin);
                 }
                 return false;
             }
-            IntegerLessThanNode lessThan = (IntegerLessThanNode) ifTest;
+            CompareNode lessThan = (CompareNode) ifTest;
             Condition condition = null;
             InductionVariable iv = null;
             ValueNode limit = null;
@@ -198,6 +198,9 @@
                     limit = lessThan.getY();
                 }
             }
+            if (iv != null && iv.isConstantStride() && iv.constantStride() != 1 && !(ifTest instanceof IntegerLessThanNode)) {
+                return false;
+            }
             if (condition == null) {
                 return false;
             }
@@ -206,6 +209,24 @@
             }
             boolean oneOff = false;
             switch (condition) {
+                case EQ:
+                    return false;
+                case NE: {
+                    IntegerStamp initStamp = (IntegerStamp) iv.initNode().stamp();
+                    IntegerStamp limitStamp = (IntegerStamp) limit.stamp();
+                    if (iv.direction() == Direction.Up) {
+                        if (initStamp.upperBound() > limitStamp.lowerBound()) {
+                            return false;
+                        }
+                    } else {
+                        assert iv.direction() == Direction.Down;
+                        if (initStamp.lowerBound() < limitStamp.upperBound()) {
+                            return false;
+                        }
+                    }
+                    oneOff = true;
+                    break;
+                }
                 case LE:
                     oneOff = true; // fall through
                 case LT:
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Mon Mar 02 19:11:22 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/LoopTransformations.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Mon Mar 02 19:11:22 2015 +0100
@@ -68,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);
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopUnswitchingPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -43,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) {
--- a/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodeinfo.processor/src/com/oracle/graal/nodeinfo/processor/GraphNodeProcessor.java	Mon Mar 02 19:11:22 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.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -33,17 +33,18 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
 
 @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
@@ -62,8 +63,13 @@
     }
 
     public static AbstractBeginNode prevBegin(FixedNode from) {
-        for (AbstractBeginNode begin : GraphUtil.predecessorIterable(from).filter(AbstractBeginNode.class)) {
-            return begin;
+        Node next = from;
+        while (next != null) {
+            if (next instanceof AbstractBeginNode) {
+                AbstractBeginNode begin = (AbstractBeginNode) next;
+                return begin;
+            }
+            next = next.predecessor();
         }
         return null;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractDeoptimizeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractFixedGuardNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractLocalNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMemoryCheckpoint.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractMergeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BinaryOpLogicNode.java	Mon Mar 02 19:11:22 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;
@@ -55,4 +58,29 @@
     @Override
     public void generate(NodeLIRBuilderTool gen) {
     }
+
+    /**
+     * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order the
+     * inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on the node
+     * if it's currently in a graph.
+     *
+     * @return the original node or another node with the same inputs, ignoring ordering.
+     */
+    @SuppressWarnings("deprecation")
+    public LogicNode maybeCommuteInputs() {
+        assert this instanceof BinaryCommutative;
+        if (x.getId() > y.getId()) {
+            ValueNode tmp = x;
+            x = y;
+            y = tmp;
+            if (graph() != null) {
+                // See if this node already exists
+                LogicNode duplicate = graph().findDuplicate(this);
+                if (duplicate != null) {
+                    return duplicate;
+                }
+            }
+        }
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BreakpointNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/CallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConditionAnchorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSinkNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizeNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -23,23 +23,27 @@
 package com.oracle.graal.nodes;
 
 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.spi.*;
 
 @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
 public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
+    public static final int DEFAULT_DEBUG_ID = 0;
 
+    public static final NodeClass<DeoptimizeNode> TYPE = NodeClass.create(DeoptimizeNode.class);
     protected final DeoptimizationAction action;
     protected final DeoptimizationReason reason;
     protected final int debugId;
     protected final JavaConstant speculation;
 
     public DeoptimizeNode(DeoptimizationAction action, DeoptimizationReason reason) {
-        this(action, reason, 0, JavaConstant.NULL_POINTER, null);
+        this(action, reason, DEFAULT_DEBUG_ID, JavaConstant.NULL_POINTER, null);
     }
 
     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;
@@ -62,14 +66,23 @@
         tool.getLowerer().lower(this, tool);
     }
 
+    @SuppressWarnings("deprecation")
+    public int getDebugId() {
+        int deoptDebugId = debugId;
+        if (deoptDebugId == DEFAULT_DEBUG_ID && (Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod())) {
+            deoptDebugId = this.getId();
+        }
+        return deoptDebugId;
+    }
+
     @Override
     public void generate(NodeLIRBuilderTool gen) {
-        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, debugId), speculation, gen.state(this));
+        gen.getLIRGeneratorTool().emitDeoptimize(gen.getLIRGeneratorTool().getMetaAccess().encodeDeoptActionAndReason(action, reason, getDebugId()), speculation, gen.state(this));
     }
 
     @Override
     public ValueNode getActionAndReason(MetaAccessProvider metaAccess) {
-        return ConstantNode.forConstant(metaAccess.encodeDeoptActionAndReason(action, reason, debugId), metaAccess, graph());
+        return ConstantNode.forConstant(metaAccess.encodeDeoptActionAndReason(action, reason, getDebugId()), metaAccess, graph());
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DeoptimizingFixedWithNextNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DirectCallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DispatchBeginNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DynamicDeoptimizeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingAnchoredNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FloatingGuardedNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Mar 02 19:11:22 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;
@@ -249,14 +251,20 @@
      * changed to newBci.
      */
     private FrameState duplicateModified(int newBci, boolean newRethrowException, boolean newDuringCall, Kind popKind, ValueNode... pushedValues) {
-        ArrayList<ValueNode> copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
-        if (popKind != Kind.Void) {
-            if (stackAt(stackSize() - 1) == null) {
+        ArrayList<ValueNode> copy;
+        if (newRethrowException && !rethrowException && popKind == Kind.Void) {
+            assert popKind == Kind.Void;
+            copy = new ArrayList<>(values.subList(0, localsSize));
+        } else {
+            copy = new ArrayList<>(values.subList(0, localsSize + stackSize));
+            if (popKind != Kind.Void) {
+                if (stackAt(stackSize() - 1) == null) {
+                    copy.remove(copy.size() - 1);
+                }
+                ValueNode lastSlot = copy.get(copy.size() - 1);
+                assert lastSlot.getKind().getStackKind() == popKind.getStackKind();
                 copy.remove(copy.size() - 1);
             }
-            ValueNode lastSlot = copy.get(copy.size() - 1);
-            assert lastSlot.getKind().getStackKind() == popKind.getStackKind();
-            copy.remove(copy.size() - 1);
         }
         for (ValueNode node : pushedValues) {
             copy.add(node);
@@ -267,7 +275,7 @@
         int newStackSize = copy.size() - localsSize;
         copy.addAll(values.subList(localsSize + stackSize, values.size()));
 
-        assert checkStackDepth(bci, stackSize, duringCall, newBci, newStackSize, newDuringCall);
+        assert checkStackDepth(bci, stackSize, duringCall, rethrowException, newBci, newStackSize, newDuringCall, newRethrowException);
         return graph().add(new FrameState(outerFrameState(), method, newBci, copy, localsSize, newStackSize, newRethrowException, newDuringCall, monitorIds, virtualObjectMappings));
     }
 
@@ -275,7 +283,7 @@
      * Perform a few sanity checks on the transformation of the stack state. The current expectation
      * is that a stateAfter is being transformed into a stateDuring, so the stack depth may change.
      */
-    private boolean checkStackDepth(int oldBci, int oldStackSize, boolean oldDuringCall, int newBci, int newStackSize, boolean newDuringCall) {
+    private boolean checkStackDepth(int oldBci, int oldStackSize, boolean oldDuringCall, boolean oldRethrowException, int newBci, int newStackSize, boolean newDuringCall, boolean newRethrowException) {
         /*
          * It would be nice to have a complete check of the shape of the FrameState based on a
          * dataflow of the bytecodes but for now just check for obvious expression stack depth
@@ -288,7 +296,7 @@
         }
         byte newCode = codes[newBci];
         if (oldBci == newBci) {
-            assert oldStackSize == newStackSize || oldDuringCall != newDuringCall : "bci is unchanged, stack depth shouldn't change";
+            assert oldStackSize == newStackSize || oldDuringCall != newDuringCall || oldRethrowException != newRethrowException : "bci is unchanged, stack depth shouldn't change";
         } else {
             byte oldCode = codes[oldBci];
             assert Bytecodes.lengthOf(newCode) + newBci == oldBci || Bytecodes.lengthOf(oldCode) + oldBci == newBci : "expecting roll back or forward";
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FullInfopointNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FullInfopointNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardPhiNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardedValueNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import static com.oracle.graal.graph.Edges.Type.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -47,7 +45,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 +69,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;
@@ -95,6 +94,10 @@
         return falseSuccessor;
     }
 
+    public double getTrueSuccessorProbability() {
+        return this.trueSuccessorProbability;
+    }
+
     public void setTrueSuccessor(AbstractBeginNode node) {
         updatePredecessor(trueSuccessor, node);
         trueSuccessor = node;
@@ -234,16 +237,16 @@
             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)) {
+                    if (nodeClass.getInputEdges().areEqualIn(trueNext, falseNext) && trueNext.valueEquals(falseNext)) {
                         falseNext.replaceAtUsages(trueNext);
                         graph().removeFixed(falseNext);
                         GraphUtil.unlinkFixedNode(trueNext);
                         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) {
@@ -365,6 +368,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;
@@ -382,44 +395,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;
                 }
             }
@@ -476,6 +453,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());
@@ -516,7 +603,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) {
@@ -559,6 +645,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) {
@@ -663,7 +752,7 @@
         MergeNode falseMerge = null;
         assert merge.stateAfter() == null;
 
-        for (AbstractEndNode end : merge.forwardEnds().snapshot()) {
+        for (EndNode end : merge.forwardEnds().snapshot()) {
             Node value = phi.valueAt(end);
             Node result = null;
             if (condition() instanceof Canonicalizable.Binary<?>) {
@@ -819,7 +908,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);
@@ -833,8 +922,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();
@@ -843,9 +932,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);
@@ -975,7 +1064,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);
@@ -989,7 +1078,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IndirectCallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InfopointNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/KillingBeginNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConstantNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNegationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoweredCallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryMapNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Mon Mar 02 19:11:22 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,27 @@
  */
 @NodeInfo
 public final class MergeNode extends AbstractMergeNode {
+
+    public static final NodeClass<MergeNode> TYPE = NodeClass.create(MergeNode.class);
+
     public MergeNode() {
+        super(TYPE);
+    }
+
+    public static void removeMergeIfDegenerated(MergeNode node) {
+        if (node.forwardEndCount() == 1 && node.hasNoUsages()) {
+            FixedNode currentNext = node.next();
+            node.setNext(null);
+            EndNode forwardEnd = node.forwardEndAt(0);
+            forwardEnd.replaceAtPredecessor(currentNext);
+            node.markDeleted();
+            forwardEnd.markDeleted();
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(this.forwardEndCount() > 1, "Must merge more than one end.");
+        return true;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon Mar 02 19:11:22 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,12 +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) {
         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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ReturnNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SafepointNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ShortCircuitOrNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/SimpleInfopointNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon Mar 02 19:11:22 2015 +0100
@@ -151,7 +151,7 @@
 
     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) {
@@ -246,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;
             }
@@ -255,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;
@@ -299,7 +299,7 @@
     }
 
     public boolean hasLoops() {
-        return hasNode(LoopBeginNode.class);
+        return hasNode(LoopBeginNode.TYPE);
     }
 
     public void removeFloating(FloatingNode node) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/TypeProfileProxyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnaryOpLogicNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/UnwindNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNodeUtil.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/VirtualState.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AbsNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AddNode.java	Mon Mar 02 19:11:22 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,8 @@
 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.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -33,10 +35,16 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "+")
-public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode {
+public class AddNode extends BinaryArithmeticNode<Add> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
+
+    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) {
@@ -46,7 +54,7 @@
         if (tryConstantFold != null) {
             return tryConstantFold;
         } else {
-            return new AddNode(x, y);
+            return new AddNode(x, y).maybeCommuteInputs();
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/AndNode.java	Mon Mar 02 19:11:22 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,10 @@
 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;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.And;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,10 +37,23 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "&")
-public final class AndNode extends BinaryArithmeticNode<And> implements NarrowableArithmeticNode {
+public final class AndNode extends BinaryArithmeticNode<And> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
+
+    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).maybeCommuteInputs();
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryArithmeticNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -37,15 +37,17 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo
-public abstract class BinaryArithmeticNode<OP> extends BinaryNode implements ArithmeticLIRLowerable {
+public abstract class BinaryArithmeticNode<OP> extends BinaryNode implements ArithmeticLIRLowerable, Canonicalizable.Binary<ValueNode> {
+
+    @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;
     }
 
@@ -250,4 +252,30 @@
         }
         return false;
     }
+
+    /**
+     * Ensure a canonical ordering of inputs for commutative nodes to improve GVN results. Order the
+     * inputs by increasing {@link Node#id} and call {@link Graph#findDuplicate(Node)} on the node
+     * if it's currently in a graph. It's assumed that if there was a constant on the left it's been
+     * moved to the right by other code and that ordering is left alone.
+     *
+     * @return the original node or another node with the same input ordering
+     */
+    @SuppressWarnings("deprecation")
+    public BinaryNode maybeCommuteInputs() {
+        assert this instanceof BinaryCommutative;
+        if (!y.isConstant() && x.getId() > y.getId()) {
+            ValueNode tmp = x;
+            x = y;
+            y = tmp;
+            if (graph() != null) {
+                // See if this node already exists
+                BinaryNode duplicate = graph().findDuplicate(this);
+                if (duplicate != null) {
+                    return duplicate;
+                }
+            }
+        }
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/BinaryNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Mon Mar 02 19:11:22 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.*;
@@ -37,8 +38,9 @@
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
 @NodeInfo
-public abstract class CompareNode extends BinaryOpLogicNode {
+public abstract class CompareNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode> {
 
+    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());
 
                 }
             }
@@ -166,7 +168,8 @@
     }
 
     public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
-        return graph.unique(createCompareNode(condition, x, y, constantReflection));
+        LogicNode result = createCompareNode(condition, x, y, constantReflection);
+        return (result.graph() == null ? graph.unique(result) : result);
     }
 
     public static LogicNode createCompareNode(Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Mon Mar 02 19:11:22 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,7 +55,7 @@
     }
 
     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;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/DivNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FixedBinaryNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatConvertNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,16 +26,19 @@
 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.Canonicalizable.BinaryCommutative;
 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 final class FloatEqualsNode extends CompareNode {
+public final class FloatEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
+    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());
     }
@@ -45,7 +48,7 @@
         if (result != null) {
             return result;
         } else {
-            return new FloatEqualsNode(x, y);
+            return new FloatEqualsNode(x, y).maybeCommuteInputs();
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowNode.java	Mon Mar 02 19:11:22 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, tool.getConstantReflection()));
+            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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerConvertNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Mon Mar 02 19:11:22 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,8 +22,6 @@
  */
 package com.oracle.graal.nodes.calc;
 
-import static com.oracle.graal.graph.Edges.Type.*;
-
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -33,10 +31,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,8 +93,8 @@
         }
 
         if (next() instanceof IntegerDivNode) {
-            NodeClass nodeClass = getNodeClass();
-            if (next().getClass() == this.getClass() && nodeClass.getEdges(Inputs).areEqualIn(this, next()) && valueEquals(next())) {
+            NodeClass<?> nodeClass = getNodeClass();
+            if (next().getClass() == this.getClass() && nodeClass.getInputEdges().areEqualIn(this, next()) && valueEquals(next())) {
                 return next();
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,16 +26,19 @@
 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.Canonicalizable.BinaryCommutative;
 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 final class IntegerEqualsNode extends CompareNode {
+public final class IntegerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
+    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,7 +48,25 @@
         if (result != null) {
             return result;
         } else {
-            return new IntegerEqualsNode(x, y);
+            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).maybeCommuteInputs();
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerRemNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerTestNode.java	Mon Mar 02 19:11:22 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,8 @@
 package com.oracle.graal.nodes.calc;
 
 import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
@@ -33,10 +35,11 @@
  * both x and y.
  */
 @NodeInfo
-public class IntegerTestNode extends BinaryOpLogicNode {
+public final class IntegerTestNode extends BinaryOpLogicNode implements BinaryCommutative<ValueNode> {
+    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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/LeftShiftNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/MulNode.java	Mon Mar 02 19:11:22 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
@@ -27,6 +27,8 @@
 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.graph.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,10 +36,27 @@
 import com.oracle.graal.nodes.spi.*;
 
 @NodeInfo(shortName = "*")
-public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode {
+public class MulNode extends BinaryArithmeticNode<Mul> implements NarrowableArithmeticNode, BinaryCommutative<ValueNode> {
+
+    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).maybeCommuteInputs();
+        }
     }
 
     @Override
@@ -59,33 +78,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NarrowNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NotNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/OrNode.java	Mon Mar 02 19:11:22 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,10 @@
 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;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Or;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,10 +37,23 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "|")
-public class OrNode extends BinaryArithmeticNode<Or> {
+public final class OrNode extends BinaryArithmeticNode<Or> implements BinaryCommutative<ValueNode> {
+
+    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).maybeCommuteInputs();
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/PointerEqualsNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,16 +24,24 @@
 
 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.Canonicalizable.BinaryCommutative;
 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 PointerEqualsNode extends CompareNode {
+public class PointerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
+
+    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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ReinterpretNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RemNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/RightShiftNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ShiftNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SignExtendNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SqrtNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/SubNode.java	Mon Mar 02 19:11:22 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.*;
+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,14 @@
 @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) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryArithmeticNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnaryNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedDivNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRemNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/UnsignedRightShiftNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/XorNode.java	Mon Mar 02 19:11:22 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,10 @@
 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;
 import com.oracle.graal.compiler.common.type.ArithmeticOpTable.BinaryOp.Xor;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.nodeinfo.*;
@@ -34,13 +37,26 @@
 import com.oracle.graal.nodes.util.*;
 
 @NodeInfo(shortName = "^")
-public class XorNode extends BinaryArithmeticNode<Xor> {
+public final class XorNode extends BinaryArithmeticNode<Xor> implements BinaryCommutative<ValueNode> {
+
+    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).maybeCommuteInputs();
+        }
+    }
+
     @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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ZeroExtendNode.java	Mon Mar 02 19:11:22 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/Block.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Mon Mar 02 19:11:22 2015 +0100
@@ -30,6 +30,7 @@
 
 public final class Block extends AbstractBlockBase<Block> {
 
+    public static final int DISTANCED_DOMINATOR_CACHE = 5;
     protected final AbstractBeginNode beginNode;
 
     protected FixedNode endNode;
@@ -38,6 +39,7 @@
     protected Loop<Block> loop;
 
     protected Block postdominator;
+    protected Block distancedDominatorCache;
 
     protected Block(AbstractBeginNode node) {
         this.beginNode = node;
@@ -51,6 +53,7 @@
         return endNode;
     }
 
+    @Override
     public Loop<Block> getLoop() {
         return loop;
     }
@@ -59,18 +62,22 @@
         this.loop = loop;
     }
 
+    @Override
     public int getLoopDepth() {
         return loop == null ? 0 : loop.getDepth();
     }
 
+    @Override
     public boolean isLoopHeader() {
         return getBeginNode() instanceof LoopBeginNode;
     }
 
+    @Override
     public boolean isLoopEnd() {
         return getEndNode() instanceof LoopEndNode;
     }
 
+    @Override
     public boolean isExceptionEntry() {
         Node predecessor = getBeginNode().predecessor();
         return predecessor != null && predecessor instanceof InvokeWithExceptionNode && getBeginNode() == ((InvokeWithExceptionNode) predecessor).exceptionEdge();
@@ -97,6 +104,7 @@
         return b;
     }
 
+    @Override
     public Block getPostdominator() {
         return postdominator;
     }
@@ -159,6 +167,7 @@
         return "B" + id;
     }
 
+    @Override
     public double probability() {
         return probability;
     }
@@ -167,4 +176,31 @@
         assert probability >= 0 && Double.isFinite(probability);
         this.probability = probability;
     }
+
+    public Block getDistancedDominatorCache() {
+        Block result = this.distancedDominatorCache;
+        if (result == null) {
+            Block current = this;
+            for (int i = 0; i < DISTANCED_DOMINATOR_CACHE; ++i) {
+                current = current.getDominator();
+            }
+            distancedDominatorCache = current;
+            return current;
+        } else {
+            return result;
+        }
+    }
+
+    @Override
+    public Block getDominator(int distance) {
+        Block result = this;
+        int i = 0;
+        for (; i < distance - (DISTANCED_DOMINATOR_CACHE - 1); i += DISTANCED_DOMINATOR_CACHE) {
+            result = result.getDistancedDominatorCache();
+        }
+        for (; i < distance; ++i) {
+            result = result.getDominator();
+        }
+        return result;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Mon Mar 02 19:11:22 2015 +0100
@@ -156,7 +156,7 @@
     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);
@@ -173,6 +173,7 @@
                 // First time we see this block: push all successors.
                 for (Node suxNode : block.getEndNode().cfgSuccessors()) {
                     Block suxBlock = blockFor(suxNode);
+                    assert suxBlock != null : suxNode;
                     if (suxBlock.getId() == BLOCK_ID_INITIAL) {
                         stack.add(suxBlock);
                     }
@@ -200,14 +201,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;
                 }
             }
@@ -222,6 +228,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);
                     }
                 }
             }
@@ -230,19 +240,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);
         }
     }
 
@@ -266,29 +266,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(3, "Unexpected loop exit with %s, including whole branch in the loop", sux);
-                                unexpected.add(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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/BlackholeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/ControlFlowAnchorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/DynamicCounterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/OpaqueNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/VerifyHeapNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/debug/WeakCounterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractWriteNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ArrayRangeWriteNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BranchProbabilityNode.java	Mon Mar 02 19:11:22 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;
     }
@@ -98,12 +100,17 @@
                             couldSet = true;
                             ifNodeUsages.setTrueSuccessorProbability(probabilityToSet);
                         }
+
+                        if (!couldSet && node.usages().filter(FixedGuardNode.class).isNotEmpty()) {
+                            couldSet = true;
+                        }
                     }
                 }
             }
             if (couldSet) {
-                replaceAndDelete(condition);
-                tool.addToWorkList(condition.usages());
+                ValueNode currentCondition = condition;
+                replaceAndDelete(currentCondition);
+                tool.addToWorkList(currentCondition.usages());
             } else {
                 if (!isSubstitutionGraph()) {
                     throw new GraalInternalError("Wrong usage of branch probability injection!");
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BytecodeExceptionNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ComputeAddressNode.java	Mon Mar 02 19:11:22 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;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedAccessNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FixedValueAnchorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatableAccessNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ForeignCallNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaReadNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/JavaWriteNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadHubNode.java	Mon Mar 02 19:11:22 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;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LoadMethodNode.java	Mon Mar 02 19:11:22 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 @@
  * 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;
@@ -47,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;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/LocationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon Mar 02 19:11:22 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/MemoryAccess.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MemoryAccess.java	Mon Mar 02 19:11:22 2015 +0100
@@ -32,14 +32,10 @@
 
     LocationIdentity getLocationIdentity();
 
-    default MemoryNode getLastLocationAccess() {
-        return null;
-    }
+    MemoryNode getLastLocationAccess();
 
     /**
      * @param lla the {@link MemoryNode} that represents the last kill of the location
      */
-    default void setLastLocationAccess(MemoryNode lla) {
-        // empty
-    }
+    void setLastLocationAccess(MemoryNode lla);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/NullCheckNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRLocalNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/OSRStartNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/StoreHubNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnboxNode.java	Mon Mar 02 19:11:22 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.*;
@@ -33,10 +34,11 @@
 @NodeInfo
 public final class UnboxNode extends UnaryNode implements Virtualizable, Lowerable {
 
+    public static final NodeClass<UnboxNode> TYPE = NodeClass.create(UnboxNode.class);
     protected final Kind boxingKind;
 
     protected UnboxNode(ValueNode value, Kind boxingKind) {
-        super(StampFactory.forKind(boxingKind.getStackKind()), value);
+        super(TYPE, StampFactory.forKind(boxingKind.getStackKind()), value);
         this.boxingKind = boxingKind;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeAccessNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AbstractNewObjectNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessIndexedNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Mon Mar 02 19:11:22 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,7 +49,7 @@
     }
 
     public ArrayLengthNode(ValueNode array) {
-        super(StampFactory.positiveInt());
+        super(TYPE, StampFactory.positiveInt());
         this.array = array;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndAddNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AtomicReadAndWriteNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastDynamicNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -44,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;
@@ -55,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;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ClassIsAssignableFromNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ClassIsAssignableFromNode.java	Mon Mar 02 19:11:22 2015 +0100
@@ -36,10 +36,13 @@
  */
 @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;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Mon Mar 02 19:11:22 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
@@ -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.*;
@@ -35,13 +36,14 @@
  * 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;
@@ -102,7 +104,7 @@
             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 LogicNegationNode.create(new IsNullNode(forValue));
             }
         }
         return null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadExceptionObjectNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredAtomicReadAndWriteNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoweredCompareAndSwapNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Mon Mar 02 19:11:22 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;
     }
 
@@ -243,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorEnterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorExitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MonitorIdNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewInstanceNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewMultiArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Mon Mar 02 19:11:22 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;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/SelfReplacingMethodCallTargetNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Mon Mar 02 19:11:22 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/PiPushable.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/PiPushable.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Mar 02 19:11:22 2015 +0100
@@ -73,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
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Virtualizable.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableAllocation.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/VirtualizableRoot.java	Mon Mar 02 19:11:22 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/util/GraphUtil.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,15 +24,14 @@
 
 import java.util.*;
 
+import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.virtual.*;
 
 public class GraphUtil {
 
@@ -40,7 +39,7 @@
 
         @Override
         public final boolean apply(Node n) {
-            return n instanceof FloatingNode || n instanceof VirtualState || n instanceof CallTargetNode || n instanceof VirtualObjectNode;
+            return !(n instanceof FixedNode);
         }
     };
 
@@ -50,7 +49,7 @@
             // We reached a control flow end.
             AbstractEndNode end = (AbstractEndNode) node;
             killEnd(end, tool);
-        } else {
+        } else if (node instanceof FixedNode) {
             // Normal control flow node.
             /*
              * We do not take a successor snapshot because this iterator supports concurrent
@@ -62,6 +61,7 @@
                 killCFG(successor, tool);
             }
         }
+        node.replaceAtPredecessor(null);
         propagateKill(node);
     }
 
@@ -112,21 +112,36 @@
         return FLOATING;
     }
 
-    public static void propagateKill(Node node) {
+    private static void propagateKill(Node node) {
         if (node != null && node.isAlive()) {
-            List<Node> usagesSnapshot = node.usages().filter(isFloatingNode()).snapshot();
+            node.markDeleted();
+
+            node.acceptInputs((n, in) -> {
+                if (in.isAlive()) {
+                    in.removeUsage(n);
+                    if (in.hasNoUsages() && !(in instanceof FixedNode)) {
+                        killWithUnusedFloatingInputs(in);
+                    }
+                }
+            });
 
-            // null out remaining usages
-            node.replaceAtUsages(null);
-            node.replaceAtPredecessor(null);
-            killWithUnusedFloatingInputs(node);
-
-            for (Node usage : usagesSnapshot) {
-                if (!usage.isDeleted()) {
-                    if (usage instanceof PhiNode) {
-                        usage.replaceFirstInput(node, null);
-                    } else {
-                        propagateKill(usage);
+            ArrayList<Node> usageToKill = null;
+            for (Node usage : node.usages()) {
+                if (usage.isAlive() && !(usage instanceof FixedNode)) {
+                    if (usageToKill == null) {
+                        usageToKill = new ArrayList<>();
+                    }
+                    usageToKill.add(usage);
+                }
+            }
+            if (usageToKill != null) {
+                for (Node usage : usageToKill) {
+                    if (usage.isAlive()) {
+                        if (usage instanceof PhiNode) {
+                            usage.replaceFirstInput(node, null);
+                        } else {
+                            propagateKill(usage);
+                        }
                     }
                 }
             }
@@ -134,11 +149,9 @@
     }
 
     public static void killWithUnusedFloatingInputs(Node node) {
-        List<Node> floatingInputs = node.inputs().filter(isFloatingNode()).snapshot();
         node.safeDelete();
-
-        for (Node in : floatingInputs) {
-            if (in.isAlive() && in.hasNoUsages()) {
+        for (Node in : node.inputs()) {
+            if (in.isAlive() && in.hasNoUsages() && !(in instanceof FixedNode)) {
                 killWithUnusedFloatingInputs(in);
             }
         }
@@ -241,13 +254,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();
@@ -256,14 +263,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() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/AllocatedObjectNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/CommitAllocationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/EscapeObjectState.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualArrayNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualBoxingNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualInstanceNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/virtual/VirtualObjectNode.java	Mon Mar 02 19:11:22 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;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options.test/src/com/oracle/graal/options/test/NestedBooleanOptionValueTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,128 @@
+/*
+ * 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.options.test;
+
+import static com.oracle.graal.options.test.NestedBooleanOptionValueTest.Options.*;
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.graal.options.*;
+import com.oracle.graal.options.OptionValue.OverrideScope;
+
+public class NestedBooleanOptionValueTest {
+
+    public static class Options {
+        public static final OptionValue<Boolean> Master0 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption0 = new NestedBooleanOptionValue(Master0, true);
+        public static final OptionValue<Boolean> Master1 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption1 = new NestedBooleanOptionValue(Master1, true);
+        public static final OptionValue<Boolean> Master2 = new OptionValue<>(true);
+        public static final OptionValue<Boolean> NestedOption2 = new NestedBooleanOptionValue(Master2, false);
+    }
+
+    static final OptionDescriptor master0 = new OptionDescriptor("Master0", Boolean.class, "", Options.class, "Master0", Master0);
+    static final OptionDescriptor nestedOption0 = new OptionDescriptor("NestedOption0", Boolean.class, "", Options.class, "NestedOption0", NestedOption0);
+    static final OptionDescriptor master1 = new OptionDescriptor("Master1", Boolean.class, "", Options.class, "Master1", Master1);
+    static final OptionDescriptor nestedOption1 = new OptionDescriptor("NestedOption1", Boolean.class, "", Options.class, "NestedOption1", NestedOption1);
+    static final OptionDescriptor master2 = new OptionDescriptor("Master2", Boolean.class, "", Options.class, "Master2", Master2);
+    static final OptionDescriptor nestedOption2 = new OptionDescriptor("NestedOption2", Boolean.class, "", Options.class, "NestedOption2", NestedOption2);
+
+    @Test
+    public void runOverrides() {
+        assertTrue(Master0.getValue());
+        assertTrue(NestedOption0.getValue());
+        try (OverrideScope s1 = OptionValue.override(Master0, false)) {
+            assertFalse(Master0.getValue());
+            assertFalse(NestedOption0.getValue());
+            try (OverrideScope s2 = OptionValue.override(NestedOption0, false)) {
+                assertFalse(NestedOption0.getValue());
+            }
+            try (OverrideScope s2 = OptionValue.override(NestedOption0, true)) {
+                assertTrue(NestedOption0.getValue());
+            }
+        }
+        assertTrue(Master0.getValue());
+        try (OverrideScope s1 = OptionValue.override(NestedOption0, false)) {
+            assertFalse(NestedOption0.getValue());
+        }
+        try (OverrideScope s1 = OptionValue.override(NestedOption0, true)) {
+            assertTrue(NestedOption0.getValue());
+        }
+    }
+
+    @Test
+    public void runDefaultTrue() {
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+        // nested value unset
+        Master1.setValue(false);
+        assertFalse(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        // set false
+        Master1.setValue(false);
+        NestedOption1.setValue(false);
+        assertFalse(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertFalse(NestedOption1.getValue());
+        // set true
+        Master1.setValue(false);
+        NestedOption1.setValue(true);
+        assertFalse(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+        Master1.setValue(true);
+        assertTrue(Master1.getValue());
+        assertTrue(NestedOption1.getValue());
+    }
+
+    @Test
+    public void runDefaultFalse() {
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // nested value unset
+        Master2.setValue(false);
+        assertFalse(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // set false
+        Master2.setValue(false);
+        NestedOption2.setValue(false);
+        assertFalse(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertFalse(NestedOption2.getValue());
+        // set true
+        Master2.setValue(false);
+        NestedOption2.setValue(true);
+        assertFalse(Master2.getValue());
+        assertTrue(NestedOption2.getValue());
+        Master2.setValue(true);
+        assertTrue(Master2.getValue());
+        assertTrue(NestedOption2.getValue());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.options/src/com/oracle/graal/options/NestedBooleanOptionValue.java	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,58 @@
+/*
+ * 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.options;
+
+/**
+ * A nested Boolean {@link OptionValue} that can be overridden by a {@link #masterOption master
+ * option}.
+ * <p>
+ * <li>If the option is present on the command line the specified value is used.
+ * <li>Otherwise {@link #getValue()} depends on the {@link #masterOption} and evaluates as follows:
+ * <ul>
+ * <li>If {@link #masterOption} is set, this value equals to {@link #initialValue}.
+ * <li>Otherwise, if {@link #masterOption} is {@code false}, this option is {@code false}.
+ */
+public class NestedBooleanOptionValue extends OptionValue<Boolean> {
+    private final OptionValue<Boolean> masterOption;
+    private final Boolean initialValue;
+
+    public NestedBooleanOptionValue(OptionValue<Boolean> masterOption, Boolean initialValue) {
+        super(null);
+        this.masterOption = masterOption;
+        this.initialValue = initialValue;
+    }
+
+    public OptionValue<Boolean> getMasterOption() {
+        return masterOption;
+    }
+
+    @Override
+    public Boolean getValue() {
+        Boolean v = super.getValue();
+        if (v == null) {
+            return initialValue && masterOption.getValue();
+        }
+        return v;
+    }
+
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.graph.Graph.NodeEventListener;
 import com.oracle.graal.graph.Graph.NodeEventScope;
 import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.graph.spi.Canonicalizable.BinaryCommutative;
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -187,7 +188,7 @@
             if (node.isAlive()) {
                 METRIC_PROCESSED_NODES.increment();
 
-                NodeClass nodeClass = node.getNodeClass();
+                NodeClass<?> nodeClass = node.getNodeClass();
                 if (tryGlobalValueNumbering(node, nodeClass)) {
                     return;
                 }
@@ -213,7 +214,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) {
@@ -228,7 +229,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)) {
@@ -254,13 +255,16 @@
             }
         }
 
-        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)) {
                     Node canonical;
                     try (AutoCloseable verify = getCanonicalizeableContractAssertion(node)) {
                         canonical = ((Canonicalizable) node).canonical(tool);
+                        if (canonical == node && nodeClass.isCommutative()) {
+                            canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
+                        }
                     }
                     if (performReplacement(node, canonical)) {
                         return true;
@@ -311,9 +315,6 @@
                 if (canonical != null && !canonical.isAlive()) {
                     assert !canonical.isDeleted();
                     canonical = graph.addOrUniqueWithInputs(canonical);
-                    if (canonical == node) {
-                        graph.addOrUniqueWithInputs(newCanonical);
-                    }
                 }
                 if (node instanceof FloatingNode) {
                     if (canonical == null) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CleanTypeProfileProxyPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
 
 /**
  * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
@@ -48,7 +49,7 @@
  * {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
  *
  */
-public class ConvertDeoptimizeToGuardPhase extends Phase {
+public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
     private SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, false);
 
     private static AbstractBeginNode findBeginNode(FixedNode startNode) {
@@ -56,56 +57,81 @@
     }
 
     @Override
-    protected void run(final StructuredGraph graph) {
+    protected void run(final StructuredGraph graph, PhaseContext context) {
         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)) {
-
-            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();
-
-                    Constant[] xs = IfNode.constantValues(compare.getX(), merge, true);
-                    if (xs == null) {
-                        continue;
-                    }
-                    Constant[] ys = IfNode.constantValues(compare.getY(), merge, true);
-                    if (ys == null) {
-                        continue;
-                    }
-                    for (int i = 0; i < mergePredecessors.size(); ++i) {
-                        AbstractEndNode mergePredecessor = mergePredecessors.get(i);
-                        if (!mergePredecessor.isAlive()) {
-                            break;
-                        }
-                        if (xs[i] == null) {
-                            continue;
-                        }
-                        if (ys[i] == null) {
-                            continue;
-                        }
-                        if (xs[i] instanceof PrimitiveConstant && ys[i] instanceof PrimitiveConstant &&
-                                        compare.condition().foldCondition(xs[i], ys[i], null, compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
-                            visitDeoptBegin(AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), graph);
-                        }
-                    }
-                }
+        if (context != null) {
+            for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) {
+                trySplitFixedGuard(fixedGuard, context);
             }
         }
 
         new DeadCodeEliminationPhase(Optional).apply(graph);
     }
 
+    private void trySplitFixedGuard(FixedGuardNode fixedGuard, PhaseContext context) {
+        LogicNode condition = fixedGuard.condition();
+        if (condition instanceof CompareNode) {
+            CompareNode compare = (CompareNode) condition;
+            ValueNode x = compare.getX();
+            ValuePhiNode xPhi = (x instanceof ValuePhiNode) ? (ValuePhiNode) x : null;
+            if (x instanceof ConstantNode || xPhi != null) {
+                ValueNode y = compare.getY();
+                ValuePhiNode yPhi = (y instanceof ValuePhiNode) ? (ValuePhiNode) y : null;
+                if (y instanceof ConstantNode || yPhi != null) {
+                    processFixedGuardAndPhis(fixedGuard, context, compare, x, xPhi, y, yPhi);
+                }
+            }
+        }
+    }
+
+    private void processFixedGuardAndPhis(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi) {
+        AbstractBeginNode pred = AbstractBeginNode.prevBegin(fixedGuard);
+        if (pred instanceof AbstractMergeNode) {
+            AbstractMergeNode merge = (AbstractMergeNode) pred;
+            if (xPhi != null && xPhi.merge() != merge) {
+                return;
+            }
+            if (yPhi != null && yPhi.merge() != merge) {
+                return;
+            }
+
+            processFixedGuardAndMerge(fixedGuard, context, compare, x, xPhi, y, yPhi, merge);
+        }
+    }
+
+    private void processFixedGuardAndMerge(FixedGuardNode fixedGuard, PhaseContext context, CompareNode compare, ValueNode x, ValuePhiNode xPhi, ValueNode y, ValuePhiNode yPhi, AbstractMergeNode merge) {
+        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        for (int i = 0; i < mergePredecessors.size(); ++i) {
+            AbstractEndNode mergePredecessor = mergePredecessors.get(i);
+            if (!mergePredecessor.isAlive()) {
+                break;
+            }
+            Constant xs;
+            if (xPhi == null) {
+                xs = x.asConstant();
+            } else {
+                xs = xPhi.valueAt(mergePredecessor).asConstant();
+            }
+            Constant ys;
+            if (yPhi == null) {
+                ys = y.asConstant();
+            } else {
+                ys = yPhi.valueAt(mergePredecessor).asConstant();
+            }
+            if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
+                visitDeoptBegin(AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.graph());
+            }
+        }
+    }
+
     private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, StructuredGraph graph) {
         if (deoptBegin instanceof AbstractMergeNode) {
             AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Options.*;
 
+import java.util.function.*;
+
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
@@ -70,93 +72,52 @@
         if (optional && ReduceDCE.getValue()) {
             return;
         }
+
         NodeFlood flood = graph.createNodeFlood();
-
+        int totalNodeCount = graph.getNodeCount();
         flood.add(graph.start());
-        iterateSuccessors(flood);
-        disconnectCFGNodes(flood, graph);
-        iterateInputs(flood, graph);
+        iterateSuccessorsAndInputs(flood);
+        int totalMarkedCount = flood.getTotalMarkedCount();
+        if (totalNodeCount == totalMarkedCount) {
+            // All nodes are live => nothing more to do.
+            return;
+        } else {
+            // Some nodes are not marked alive and therefore dead => proceed.
+            assert totalNodeCount > totalMarkedCount;
+        }
+
         deleteNodes(flood, graph);
-
-        // remove chained Merges
-        for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.class)) {
-            if (merge.forwardEndCount() == 1 && !(merge instanceof LoopBeginNode)) {
-                graph.reduceTrivialMerge(merge);
-            }
-        }
     }
 
-    private static void iterateSuccessors(NodeFlood flood) {
+    private static void iterateSuccessorsAndInputs(NodeFlood flood) {
+        BiConsumer<Node, Node> consumer = (n, succOrInput) -> {
+            assert succOrInput.isAlive() : succOrInput;
+            flood.add(succOrInput);
+        };
         for (Node current : flood) {
             if (current instanceof AbstractEndNode) {
                 AbstractEndNode end = (AbstractEndNode) current;
                 flood.add(end.merge());
             } else {
-                for (Node successor : current.successors()) {
-                    flood.add(successor);
-                }
-            }
-        }
-    }
-
-    private static void disconnectCFGNodes(NodeFlood flood, StructuredGraph graph) {
-        for (AbstractEndNode node : graph.getNodes(AbstractEndNode.class)) {
-            if (!flood.isMarked(node)) {
-                AbstractMergeNode merge = node.merge();
-                if (merge != null && flood.isMarked(merge)) {
-                    // We are a dead end node leading to a live merge.
-                    merge.removeEnd(node);
-                }
-            }
-        }
-        for (LoopBeginNode loop : graph.getNodes(LoopBeginNode.class)) {
-            if (flood.isMarked(loop)) {
-                boolean reachable = false;
-                for (LoopEndNode end : loop.loopEnds()) {
-                    if (flood.isMarked(end)) {
-                        reachable = true;
-                        break;
-                    }
-                }
-                if (!reachable) {
-                    Debug.log("Removing loop with unreachable end: %s", loop);
-                    for (LoopEndNode end : loop.loopEnds().snapshot()) {
-                        loop.removeEnd(end);
-                    }
-                    graph.reduceDegenerateLoopBegin(loop);
-                }
+                current.acceptSuccessors(consumer);
+                current.acceptInputs(consumer);
             }
         }
     }
 
     private static void deleteNodes(NodeFlood flood, StructuredGraph graph) {
+        BiConsumer<Node, Node> consumer = (n, input) -> {
+            if (input.isAlive() && flood.isMarked(input)) {
+                input.removeUsage(n);
+            }
+        };
+
         for (Node node : graph.getNodes()) {
             if (!flood.isMarked(node)) {
-                node.clearInputs();
-                node.clearSuccessors();
-            }
-        }
-        for (Node node : graph.getNodes()) {
-            if (!flood.isMarked(node)) {
+                node.markDeleted();
+                node.acceptInputs(consumer);
                 metricNodesRemoved.increment();
-                node.safeDelete();
             }
         }
     }
-
-    private static void iterateInputs(NodeFlood flood, StructuredGraph graph) {
-        for (Node node : graph.getNodes()) {
-            if (flood.isMarked(node)) {
-                for (Node input : node.inputs()) {
-                    flood.add(input);
-                }
-            }
-        }
-        for (Node current : flood) {
-            for (Node input : current.inputs()) {
-                flood.add(input);
-            }
-        }
-    }
-
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeoptimizationGroupingPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Mon Mar 02 19:11:22 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/FloatingReadPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -45,7 +45,6 @@
 
     private boolean createFloatingReads;
     private boolean createMemoryMapNodes;
-    private boolean updateExistingPhis;
 
     public static class MemoryMapImpl implements MemoryMap {
 
@@ -90,7 +89,7 @@
     }
 
     public FloatingReadPhase() {
-        this(true, false, false);
+        this(true, false);
     }
 
     /**
@@ -99,13 +98,10 @@
      *            {@link FloatingReadNode}s) where possible
      * @param createMemoryMapNodes a {@link MemoryMapNode} will be created for each return if this
      *            is true
-     * @param updateExistingPhis if true, then existing {@link MemoryPhiNode}s in the graph will be
-     *            updated
      */
-    public FloatingReadPhase(boolean createFloatingReads, boolean createMemoryMapNodes, boolean updateExistingPhis) {
+    public FloatingReadPhase(boolean createFloatingReads, boolean createMemoryMapNodes) {
         this.createFloatingReads = createFloatingReads;
         this.createMemoryMapNodes = createMemoryMapNodes;
-        this.updateExistingPhis = updateExistingPhis;
     }
 
     /**
@@ -135,7 +131,7 @@
         ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), CollectionsFactory.newSet());
         HashSetNodeEventListener listener = new HashSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES));
         try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
-            ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes, updateExistingPhis), graph.start(), new MemoryMapImpl(graph.start()));
+            ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes), graph.start(), new MemoryMapImpl(graph.start()));
         }
 
         for (Node n : removeExternallyUsedNodes(listener.getNodes())) {
@@ -150,7 +146,7 @@
         }
     }
 
-    public static MemoryMapImpl mergeMemoryMaps(AbstractMergeNode merge, List<? extends MemoryMap> states, boolean updateExistingPhis) {
+    public static MemoryMapImpl mergeMemoryMaps(AbstractMergeNode merge, List<? extends MemoryMap> states) {
         MemoryMapImpl newState = new MemoryMapImpl();
 
         Set<LocationIdentity> keys = CollectionsFactory.newSet();
@@ -159,17 +155,6 @@
         }
         assert checkNoImmutableLocations(keys);
 
-        Map<LocationIdentity, MemoryPhiNode> existingPhis = null;
-        if (updateExistingPhis) {
-            for (MemoryPhiNode phi : merge.phis().filter(MemoryPhiNode.class)) {
-                if (existingPhis == null) {
-                    existingPhis = CollectionsFactory.newMap();
-                }
-                phi.values().clear();
-                existingPhis.put(phi.getLocationIdentity(), phi);
-            }
-        }
-
         for (LocationIdentity key : keys) {
             int mergedStatesCount = 0;
             boolean isPhi = false;
@@ -184,10 +169,7 @@
                     } else if (merged == null) {
                         merged = last;
                     } else {
-                        MemoryPhiNode phi = null;
-                        if (existingPhis == null || (phi = existingPhis.remove(key)) == null) {
-                            phi = merge.graph().addWithoutUnique(new MemoryPhiNode(merge, key));
-                        }
+                        MemoryPhiNode phi = merge.graph().addWithoutUnique(new MemoryPhiNode(merge, key));
                         for (int j = 0; j < mergedStatesCount; j++) {
                             phi.addInput(ValueNodeUtil.asNode(merged));
                         }
@@ -200,11 +182,6 @@
             }
             newState.lastMemorySnapshot.put(key, merged);
         }
-        if (existingPhis != null) {
-            for (Map.Entry<LocationIdentity, MemoryPhiNode> entry : existingPhis.entrySet()) {
-                entry.getValue().replaceAndDelete(newState.getLastLocationAccess(entry.getKey()).asNode());
-            }
-        }
         return newState;
 
     }
@@ -273,13 +250,11 @@
         private final Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops;
         private boolean createFloatingReads;
         private boolean createMemoryMapNodes;
-        private boolean updateExistingPhis;
 
-        public FloatingReadClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops, boolean createFloatingReads, boolean createMemoryMapNodes, boolean updateExistingPhis) {
+        public FloatingReadClosure(Map<LoopBeginNode, Set<LocationIdentity>> modifiedInLoops, boolean createFloatingReads, boolean createMemoryMapNodes) {
             this.modifiedInLoops = modifiedInLoops;
             this.createFloatingReads = createFloatingReads;
             this.createMemoryMapNodes = createMemoryMapNodes;
-            this.updateExistingPhis = updateExistingPhis;
         }
 
         @Override
@@ -347,7 +322,7 @@
 
         @Override
         protected MemoryMapImpl merge(AbstractMergeNode merge, List<MemoryMapImpl> states) {
-            return mergeMemoryMaps(merge, states, updateExistingPhis);
+            return mergeMemoryMaps(merge, states);
         }
 
         @Override
@@ -378,24 +353,10 @@
 
             Map<LocationIdentity, MemoryPhiNode> phis = CollectionsFactory.newMap();
 
-            if (updateExistingPhis) {
-                for (MemoryPhiNode phi : loop.phis().filter(MemoryPhiNode.class).snapshot()) {
-                    if (modifiedLocations.contains(phi.getLocationIdentity())) {
-                        phi.values().clear();
-                        phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(phi.getLocationIdentity())));
-                        phis.put(phi.getLocationIdentity(), phi);
-                    } else {
-                        phi.replaceAndDelete(initialState.getLastLocationAccess(phi.getLocationIdentity()).asNode());
-                    }
-                }
-            }
-
             for (LocationIdentity location : modifiedLocations) {
-                if (!updateExistingPhis || !phis.containsKey(location)) {
-                    MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
-                    phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
-                    phis.put(location, phi);
-                }
+                MemoryPhiNode phi = loop.graph().addWithoutUnique(new MemoryPhiNode(loop, location));
+                phi.addInput(ValueNodeUtil.asNode(initialState.getLastLocationAccess(location)));
+                phis.put(location, phi);
             }
             for (Map.Entry<LocationIdentity, MemoryPhiNode> entry : phis.entrySet()) {
                 initialState.lastMemorySnapshot.put(entry.getKey(), entry.getValue());
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java	Mon Mar 02 19:11:22 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/GuardLoweringPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -163,7 +163,8 @@
             StructuredGraph graph = guard.graph();
             AbstractBeginNode fastPath = graph.add(new BeginNode());
             @SuppressWarnings("deprecation")
-            DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason(), useGuardIdAsDebugId ? guard.getId() : 0, guard.getSpeculation(), null));
+            int debugId = useGuardIdAsDebugId ? guard.getId() : DeoptimizeNode.DEFAULT_DEBUG_ID;
+            DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason(), debugId, guard.getSpeculation(), null));
             AbstractBeginNode deoptBranch = BeginNode.begin(deopt);
             AbstractBeginNode trueSuccessor;
             AbstractBeginNode falseSuccessor;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LockEliminationPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoopSafepointInsertionPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Mon Mar 02 19:11:22 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
@@ -47,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;
         }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/NonNullParametersPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/OptimizeGuardAnchorsPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/PushThroughPiPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/RemoveValueProxyPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/UseTrappingNullChecksPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/VerifyHeapAtReturnPhase.java	Mon Mar 02 19:11:22 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/InliningUtil.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon Mar 02 19:11:22 2015 +0100
@@ -331,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);
                 }
@@ -389,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);
         }
@@ -410,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/AbstractInlineInfo.java	Mon Mar 02 19:11:22 2015 +0100
@@ -73,7 +73,7 @@
     }
 
     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()) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Mon Mar 02 19:11:22 2015 +0100
@@ -226,8 +226,10 @@
         assert invoke.next() == continuation;
         invoke.setNext(null);
         returnMerge.setNext(continuation);
-        invoke.asNode().replaceAtUsages(returnValuePhi);
-        invoke.asNode().replaceAndDelete(null);
+        if (returnValuePhi != null) {
+            invoke.asNode().replaceAtUsages(returnValuePhi);
+        }
+        invoke.asNode().safeDelete();
 
         ArrayList<GuardedValueNode> replacementNodes = new ArrayList<>();
 
@@ -464,7 +466,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);
 
@@ -499,7 +501,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);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/elem/InlineableGraph.java	Mon Mar 02 19:11:22 2015 +0100
@@ -143,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
@@ -211,7 +211,7 @@
             if (context.getGraphBuilderSuite() != null) {
                 context.getGraphBuilderSuite().apply(newGraph, context);
             }
-            assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite";
+            assert newGraph.start().next() != null : "graph needs to be populated by the GraphBuilderSuite " + method + ", " + method.canBeInlined();
 
             new DeadCodeEliminationPhase(Optional).apply(newGraph);
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/CallsiteHolderExplorable.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/ComputeInliningRelevance.java	Mon Mar 02 19:11:22 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/src/com/oracle/graal/phases/VerifyPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/VerifyPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java	Mon Mar 02 19:11:22 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/InferStamps.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/InferStamps.java	Mon Mar 02 19:11:22 2015 +0100
@@ -56,6 +56,8 @@
         }
 
         boolean stampChanged;
+        // The algorithm is not guaranteed to reach a stable state.
+        int z = 0;
         do {
             stampChanged = false;
             /*
@@ -72,7 +74,8 @@
                     }
                 }
             }
-        } while (stampChanged);
+            ++z;
+        } while (stampChanged && z < 10000);
 
         /*
          * Check that all the illegal stamps we introduced above are correctly replaced with real
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScheduledNodeIterator.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Mar 02 19:11:22 2015 +0100
@@ -322,11 +322,11 @@
     @Override
     protected void run(StructuredGraph graph) {
         assert GraphOrder.assertNonCyclicGraph(graph);
-        cfg = ControlFlowGraph.compute(graph, true, true, true, true);
+        cfg = ControlFlowGraph.compute(graph, true, true, true, false);
         earliestCache = graph.createNodeMap();
         blockToNodesMap = new BlockMap<>(cfg);
 
-        if (selectedStrategy != SchedulingStrategy.EARLIEST) {
+        if (selectedStrategy != SchedulingStrategy.EARLIEST && graph.isAfterFloatingReadPhase()) {
             blockToKillSet = new BlockMap<>(cfg);
         }
 
@@ -359,7 +359,6 @@
         for (Block b : getCFG().getBlocks()) {
             buf.format("==== b: %s (loopDepth: %s). ", b, b.getLoopDepth());
             buf.format("dom: %s. ", b.getDominator());
-            buf.format("post-dom: %s. ", b.getPostdominator());
             buf.format("preds: %s. ", b.getPredecessors());
             buf.format("succs: %s ====%n", b.getSuccessors());
             BlockMap<LocationSet> killSets = blockToKillSet;
@@ -621,42 +620,23 @@
      * @param earliestBlock
      */
     private Block latestBlock(ValueNode node, SchedulingStrategy strategy, Block earliestBlock) {
-        CommonDominatorBlockClosure cdbc = new CommonDominatorBlockClosure(null);
-        ensureScheduledUsages(node, strategy);
+        Block block = null;
         for (Node usage : node.usages()) {
-            blocksForUsage(node, usage, cdbc, strategy);
-            if (cdbc.block == earliestBlock) {
+            block = blocksForUsage(node, usage, block, earliestBlock, strategy);
+            if (block == earliestBlock) {
                 break;
             }
         }
 
-        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 true;
+        assert assertLatestBlockResult(node, block);
+        return block;
     }
 
-    /**
-     * A closure that will calculate the common dominator of all blocks passed to its
-     * {@link #apply(Block)} method.
-     */
-    private static class CommonDominatorBlockClosure implements BlockClosure {
-
-        public Block block;
-
-        public CommonDominatorBlockClosure(Block block) {
-            this.block = block;
+    private boolean assertLatestBlockResult(ValueNode node, Block block) throws SchedulingError {
+        if (block != null && !dominates(earliestBlock(node), block)) {
+            throw new SchedulingError("failed to find correct latest schedule for %s. cdbc: %s, earliest: %s", node, block, earliestBlock(node));
         }
-
-        @Override
-        public void apply(Block newBlock) {
-            this.block = commonDominatorTyped(this.block, newBlock);
-        }
+        return true;
     }
 
     /**
@@ -671,41 +651,32 @@
         if (earliest != null) {
             return earliest;
         }
+        return earliestBlockHelper(node, earliest);
+    }
+
+    private Block earliestBlockHelper(Node node, Block earliestStart) throws SchedulingError {
         /*
          * All inputs must be in a dominating block, otherwise the graph cannot be scheduled. This
          * implies that the inputs' blocks have a total ordering via their dominance relation. So in
          * order to find the earliest block placement for this node we need to find the input block
          * that is dominated by all other input blocks.
          */
+        Block earliest = earliestStart;
 
         if (node.predecessor() != null) {
             throw new SchedulingError();
         }
-        for (Node input : node.inputs().nonNull()) {
-            assert input instanceof ValueNode;
-            Block inputEarliest;
-            if (input instanceof InvokeWithExceptionNode) {
-                inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next());
-            } else {
-                inputEarliest = earliestBlock(input);
-            }
-            if (earliest == null) {
-                earliest = inputEarliest;
-            } else if (earliest != inputEarliest) {
-                // Find out whether earliest or inputEarliest is earlier.
-                Block a = earliest.getDominator();
-                Block b = inputEarliest;
-                while (true) {
-                    if (a == inputEarliest || b == null) {
-                        // Nothing to change, the previous earliest block is still earliest.
-                        break;
-                    } else if (b == earliest || a == null) {
-                        // New earliest is the earliest.
-                        earliest = inputEarliest;
-                        break;
-                    }
-                    a = a.getDominator();
-                    b = b.getDominator();
+        for (Node input : node.inputs()) {
+            if (input != null) {
+                assert input instanceof ValueNode;
+                Block inputEarliest;
+                if (input instanceof InvokeWithExceptionNode) {
+                    inputEarliest = cfg.getNodeToBlock().get(((InvokeWithExceptionNode) input).next());
+                } else {
+                    inputEarliest = earliestBlock(input);
+                }
+                if (earliest == null || earliest.getDominatorDepth() < inputEarliest.getDominatorDepth()) {
+                    earliest = inputEarliest;
                 }
             }
         }
@@ -732,14 +703,19 @@
         }
         Block cur = latestBlock;
         Block result = latestBlock;
-        while (cur.getLoop() != null && cur != earliest && cur.getDominator() != null) {
-            Block dom = cur.getDominator();
-            if (dom.getLoopDepth() < result.getLoopDepth()) {
-                result = dom;
+        Loop<?> earliestLoop = earliest.getLoop();
+        while (true) {
+            Loop<?> curLoop = cur.getLoop();
+            if (curLoop == earliestLoop) {
+                return result;
+            } else {
+                Block dom = cur.getDominator();
+                if (dom.getLoopDepth() < result.getLoopDepth()) {
+                    result = dom;
+                }
+                cur = dom;
             }
-            cur = dom;
         }
-        return result;
     }
 
     /**
@@ -748,11 +724,11 @@
      *
      * @param node the node that needs to be scheduled
      * @param usage the usage whose blocks need to be considered
-     * @param closure the closure that will be called for each block
+     * @param earliestBlock
      */
-    private void blocksForUsage(ValueNode node, Node usage, CommonDominatorBlockClosure closure, SchedulingStrategy strategy) {
+    private Block blocksForUsage(ValueNode node, Node usage, Block startCurrentBlock, Block earliestBlock, SchedulingStrategy strategy) {
         assert !(node instanceof PhiNode);
-
+        Block currentBlock = startCurrentBlock;
         if (usage instanceof PhiNode) {
             // An input to a PhiNode is used at the end of the predecessor block that corresponds to
             // the PhiNode input.
@@ -763,7 +739,10 @@
             Block mergeBlock = cfg.getNodeToBlock().get(merge);
             for (int i = 0; i < phi.valueCount(); ++i) {
                 if (phi.valueAt(i) == node) {
-                    closure.apply(mergeBlock.getPredecessors().get(i));
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, mergeBlock.getPredecessors().get(i));
+                    if (currentBlock == earliestBlock) {
+                        break;
+                    }
                 }
             }
         } else if (usage instanceof VirtualState) {
@@ -773,19 +752,19 @@
                 if (unscheduledUsage instanceof VirtualState) {
                     // If a FrameState is an outer FrameState this method behaves as if the inner
                     // FrameState was the actual usage, by recursing.
-                    blocksForUsage(node, unscheduledUsage, closure, strategy);
+                    currentBlock = blocksForUsage(node, unscheduledUsage, currentBlock, earliestBlock, strategy);
                 } else if (unscheduledUsage instanceof AbstractBeginNode) {
                     // Only FrameStates can be connected to BeginNodes.
                     if (!(usage instanceof FrameState)) {
                         throw new SchedulingError(usage.toString());
                     }
                     if (unscheduledUsage instanceof StartNode) {
-                        closure.apply(cfg.getNodeToBlock().get(unscheduledUsage));
+                        currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(unscheduledUsage));
                     } else {
                         // If a FrameState belongs to a BeginNode then it's inputs will be placed at
                         // the common dominator of all EndNodes.
                         for (Node pred : unscheduledUsage.cfgPredecessors()) {
-                            closure.apply(cfg.getNodeToBlock().get(pred));
+                            currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(pred));
                         }
                     }
                 } else {
@@ -798,21 +777,18 @@
                     }
                     // Otherwise: Put the input into the same block as the usage.
                     assignBlockToNode((ValueNode) unscheduledUsage, strategy);
-                    closure.apply(cfg.getNodeToBlock().get(unscheduledUsage));
+                    currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(unscheduledUsage));
+                }
+                if (currentBlock == earliestBlock) {
+                    break;
                 }
             }
         } else {
             // All other types of usages: Put the input into the same block as the usage.
             assignBlockToNode((ValueNode) usage, strategy);
-            closure.apply(cfg.getNodeToBlock().get(usage));
+            currentBlock = AbstractControlFlowGraph.commonDominatorTyped(currentBlock, cfg.getNodeToBlock().get(usage));
         }
-    }
-
-    private void ensureScheduledUsages(Node node, SchedulingStrategy strategy) {
-        for (Node usage : node.usages().filter(ValueNode.class)) {
-            assignBlockToNode((ValueNode) usage, strategy);
-        }
-        // now true usages are ready
+        return currentBlock;
     }
 
     private void sortNodesWithinBlocks(StructuredGraph graph, SchedulingStrategy strategy) {
@@ -1071,20 +1047,23 @@
             return;
         }
 
+        if (i instanceof LoopExitNode) {
+            LoopExitNode loopExitNode = (LoopExitNode) i;
+            for (ProxyNode proxy : loopExitNode.proxies()) {
+                addToLatestSorting(proxy, state);
+            }
+        }
+
+        addToLatestSortingHelper(i, state);
+    }
+
+    private void addToLatestSortingHelper(ValueNode i, SortState state) {
         FrameState stateAfter = null;
         if (i instanceof StateSplit) {
             stateAfter = ((StateSplit) i).stateAfter();
         }
 
-        for (Node input : i.inputs()) {
-            if (input instanceof FrameState) {
-                if (input != stateAfter) {
-                    addUnscheduledToLatestSorting((FrameState) input, state);
-                }
-            } else {
-                addToLatestSorting((ValueNode) input, state);
-            }
-        }
+        addInputsToLatestSorting(i, state, stateAfter);
 
         if (state.readsSize() != 0) {
             if (i instanceof MemoryCheckpoint.Single) {
@@ -1112,6 +1091,18 @@
         }
     }
 
+    private void addInputsToLatestSorting(ValueNode i, SortState state, FrameState stateAfter) {
+        for (Node input : i.inputs()) {
+            if (input instanceof FrameState) {
+                if (input != stateAfter) {
+                    addUnscheduledToLatestSorting((FrameState) input, state);
+                }
+            } else {
+                addToLatestSorting((ValueNode) input, state);
+            }
+        }
+    }
+
     /**
      * Sorts the nodes within a block by adding the nodes to a list in a post-order iteration over
      * all usages. The resulting list is reversed to create an earliest-possible scheduling of
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/CompilerConfiguration.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,9 +24,9 @@
 
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.lir.phases.*;
-import com.oracle.graal.lir.phases.LIRHighTierPhase.*;
-import com.oracle.graal.lir.phases.LIRLowTierPhase.*;
-import com.oracle.graal.lir.phases.LIRMidTierPhase.*;
+import com.oracle.graal.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 {
@@ -37,9 +37,9 @@
 
     PhaseSuite<LowTierContext> createLowTier();
 
-    LIRPhaseSuite<LIRHighTierContext> createLIRHighTier();
+    LIRPhaseSuite<PreAllocationOptimizationContext> createPreAllocationOptimizationStage();
 
-    LIRPhaseSuite<LIRMidTierContext> createLIRMidTier();
+    LIRPhaseSuite<AllocationContext> createAllocationStage();
 
-    LIRPhaseSuite<LIRLowTierContext> createLIRLowTier();
+    LIRPhaseSuite<PostAllocationOptimizationContext> createPostAllocationOptimizationStage();
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/Suites.java	Mon Mar 02 19:11:22 2015 +0100
@@ -133,7 +133,8 @@
     public static LIRSuites createDefaultLIRSuites() {
         String selected = CompilerConfiguration.getValue();
         if (selected.equals("")) {
-            return new LIRSuites(defaultConfiguration.createLIRHighTier(), defaultConfiguration.createLIRMidTier(), defaultConfiguration.createLIRLowTier());
+            return new LIRSuites(defaultConfiguration.createPreAllocationOptimizationStage(), defaultConfiguration.createAllocationStage(),
+                            defaultConfiguration.createPostAllocationOptimizationStage());
         } else {
             return createLIRSuites(selected);
         }
@@ -144,7 +145,7 @@
         if (config == null) {
             throw new GraalInternalError("unknown compiler configuration: " + name);
         }
-        return new LIRSuites(config.createLIRHighTier(), config.createLIRMidTier(), config.createLIRLowTier());
+        return new LIRSuites(config.createPreAllocationOptimizationStage(), config.createAllocationStage(), config.createPostAllocationOptimizationStage());
     }
 
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/BlockWorkList.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/BlockWorkList.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/util/GraphOrder.java	Mon Mar 02 19:11:22 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;
                             }
                         });
                     }
@@ -249,7 +251,9 @@
 
                 @Override
                 protected NodeBitMap getInitialState() {
-                    return graph.createNodeBitMap();
+                    NodeBitMap ret = graph.createNodeBitMap();
+                    ret.markAll(graph.getNodes().filter(ConstantNode.class));
+                    return ret;
                 }
 
                 @Override
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/verify/VerifyDebugUsage.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon Mar 02 19:11:22 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,13 +439,14 @@
     }
 
     private void writeEdges(Node node, Edges.Type type) throws IOException {
-        NodeClass nodeClass = node.getNodeClass();
+        NodeClass<?> nodeClass = node.getNodeClass();
         Edges edges = nodeClass.getEdges(type);
+        final long[] curOffsets = edges.getOffsets();
         for (int i = 0; i < edges.getDirectCount(); i++) {
-            writeNodeRef(edges.getNode(node, i));
+            writeNodeRef(Edges.getNode(node, curOffsets, i));
         }
         for (int i = edges.getDirectCount(); i < edges.getCount(); i++) {
-            NodeList<Node> list = edges.getNodeList(node, i);
+            NodeList<Node> list = Edges.getNodeList(node, curOffsets, i);
             if (list == null) {
                 writeShort((char) 0);
             } else {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Mon Mar 02 19:11:22 2015 +0100
@@ -33,7 +33,6 @@
 import com.oracle.graal.compiler.gen.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.java.*;
-import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.alloc.lsra.*;
 import com.oracle.graal.lir.alloc.lsra.Interval.*;
@@ -131,10 +130,10 @@
      * @param label A label describing the compilation phase that produced the control flow graph.
      * @param blocks The list of blocks to be printed.
      */
-    public void printCFG(String label, List<? extends AbstractBlock<?>> blocks, boolean printNodes) {
+    public void printCFG(String label, List<? extends AbstractBlockBase<?>> blocks, boolean printNodes) {
         if (lir == null) {
             latestScheduling = new NodeMap<>(cfg.getNodeToBlock());
-            for (AbstractBlock<?> abstractBlock : blocks) {
+            for (AbstractBlockBase<?> abstractBlock : blocks) {
                 Block block = (Block) abstractBlock;
                 Node cur = block.getBeginNode();
                 while (true) {
@@ -152,7 +151,7 @@
 
         begin("cfg");
         out.print("name \"").print(label).println('"');
-        for (AbstractBlock<?> block : blocks) {
+        for (AbstractBlockBase<?> block : blocks) {
             printBlock(block, printNodes);
         }
         end("cfg");
@@ -194,7 +193,7 @@
         }
     }
 
-    private void printBlock(AbstractBlock<?> block, boolean printNodes) {
+    private void printBlock(AbstractBlockBase<?> block, boolean printNodes) {
         printBlockProlog(block);
         if (printNodes) {
             assert block instanceof Block;
@@ -203,31 +202,26 @@
         printBlockEpilog(block);
     }
 
-    private void printBlockEpilog(AbstractBlock<?> block) {
+    private void printBlockEpilog(AbstractBlockBase<?> block) {
         printLIR(block);
         end("block");
     }
 
-    private void printBlockProlog(AbstractBlock<?> block) {
+    private void printBlockProlog(AbstractBlockBase<?> block) {
         begin("block");
 
         out.print("name \"").print(blockToString(block)).println('"');
-        if (block instanceof BciBlock) {
-            out.print("from_bci ").println(((BciBlock) block).startBci);
-            out.print("to_bci ").println(((BciBlock) block).endBci);
-        } else {
-            out.println("from_bci -1");
-            out.println("to_bci -1");
-        }
+        out.println("from_bci -1");
+        out.println("to_bci -1");
 
         out.print("predecessors ");
-        for (AbstractBlock<?> pred : block.getPredecessors()) {
+        for (AbstractBlockBase<?> pred : block.getPredecessors()) {
             out.print("\"").print(blockToString(pred)).print("\" ");
         }
         out.println();
 
         out.print("successors ");
-        for (AbstractBlock<?> succ : block.getSuccessors()) {
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
             if (!succ.isExceptionEntry()) {
                 out.print("\"").print(blockToString(succ)).print("\" ");
             }
@@ -235,7 +229,7 @@
         out.println();
 
         out.print("xhandlers");
-        for (AbstractBlock<?> succ : block.getSuccessors()) {
+        for (AbstractBlockBase<?> succ : block.getSuccessors()) {
             if (succ.isExceptionEntry()) {
                 out.print("\"").print(blockToString(succ)).print("\" ");
             }
@@ -437,7 +431,7 @@
      *
      * @param block the block to print
      */
-    private void printLIR(AbstractBlock<?> block) {
+    private void printLIR(AbstractBlockBase<?> block) {
         if (lir == null) {
             return;
         }
@@ -500,7 +494,7 @@
         return prefix + node.toString(Verbosity.Id);
     }
 
-    private String blockToString(AbstractBlock<?> block) {
+    private String blockToString(AbstractBlockBase<?> block) {
         if (lir == null && schedule == null && block instanceof Block) {
             // During all the front-end phases, the block schedule is built only for the debug
             // output.
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/HexCodeFile.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64CountLeadingZerosNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64CountTrailingZerosNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.amd64/src/com/oracle/graal/replacements/amd64/AMD64FloatConvertNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -335,7 +335,7 @@
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         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};
@@ -351,7 +351,7 @@
         new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
         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() {
@@ -367,7 +367,7 @@
         new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
         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() {
@@ -385,7 +385,7 @@
         new PartialEscapePhase(false, new CanonicalizerPhase(false)).apply(graph, context);
         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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/BitOpNodesTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -253,12 +253,12 @@
         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/EdgesTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/EdgesTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -29,7 +29,6 @@
 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;
@@ -45,11 +44,13 @@
 
     @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);
         }
 
     }
@@ -72,25 +73,25 @@
         node.i1 = i1;
         node.i2 = i2;
         graph.add(node);
-        inputs = node.getNodeClass().getEdges(Type.Inputs);
+        inputs = node.getNodeClass().getInputEdges();
     }
 
     /**
      * Checks that there are no checkcasts in the compiled version of
-     * {@link Edges#getNode(Node, int)}.
+     * {@link Edges#getNode(Node, long[], int)}.
      */
     @Test
     public void test0() {
-        testMethod(getMethod("getNode", Node.class, int.class), inputs, node, 0);
+        testMethod(getMethod("getNode", Node.class, long[].class, int.class), null, node, inputs.getOffsets(), 0);
     }
 
     /**
      * Checks that there are no checkcasts in the compiled version of
-     * {@link Edges#getNodeList(Node, int)}.
+     * {@link Edges#getNodeList(Node, long[], int)}.
      */
     @Test
     public void test1() {
-        testMethod(getMethod("getNodeList", Node.class, int.class), inputs, node, 2);
+        testMethod(getMethod("getNodeList", Node.class, long[].class, int.class), null, node, inputs.getOffsets(), 2);
     }
 
     /**
--- a/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements.verifier/src/com/oracle/graal/replacements/verifier/APHotSpotSignature.java	Mon Mar 02 19:11:22 2015 +0100
@@ -149,7 +149,7 @@
 
     /**
      * Returns the kind from the character describing a primitive or void.
-     * 
+     *
      * @param ch the character
      * @return the kind
      */
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/EdgesSubstitutions.java	Mon Mar 02 19:11:22 2015 +0100
@@ -40,22 +40,12 @@
 public class EdgesSubstitutions {
 
     @MethodSubstitution
-    private static Node getNode(Node node, long offset) {
+    private static Node getNodeUnsafe(Node node, long offset) {
         return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), Node.class);
     }
 
     @MethodSubstitution
-    private static NodeList<?> getNodeList(Node node, long offset) {
+    private static NodeList<?> getNodeListUnsafe(Node node, long offset) {
         return PiNode.piCast(UnsafeLoadNode.load(node, offset, Kind.Object, LocationIdentity.ANY_LOCATION), NodeList.class);
     }
-
-    @MethodSubstitution
-    private static void putNode(Node node, long offset, Node value) {
-        UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
-
-    @MethodSubstitution
-    private static void putNodeList(Node node, long offset, NodeList<?> value) {
-        UnsafeStoreNode.store(node, offset, value, Kind.Object, LocationIdentity.ANY_LOCATION);
-    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Log.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationPhase.java	Mon Mar 02 19:11:22 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);
@@ -226,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;
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeIntrinsificationVerificationPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Mar 02 19:11:22 2015 +0100
@@ -64,6 +64,7 @@
     public final Providers providers;
     public final SnippetReflectionProvider snippetReflection;
     public final TargetDescription target;
+    public final NodeIntrinsificationPhase nodeIntrinsificationPhase;
 
     /**
      * The preprocessed replacement graphs.
@@ -227,6 +228,7 @@
         this.target = target;
         this.graphs = new ConcurrentHashMap<>();
         this.snippetTemplateCache = CollectionsFactory.newMap();
+        this.nodeIntrinsificationPhase = createNodeIntrinsificationPhase();
     }
 
     private static final boolean UseSnippetGraphCache = Boolean.parseBoolean(System.getProperty("graal.useSnippetGraphCache", "true"));
@@ -285,7 +287,7 @@
 
         // Do deferred intrinsification of node intrinsics
 
-        createNodeIntrinsificationPhase().apply(specializedSnippet);
+        nodeIntrinsificationPhase.apply(specializedSnippet);
         new CanonicalizerPhase(true).apply(specializedSnippet, new PhaseContext(providers));
         NodeIntrinsificationVerificationPhase.verify(specializedSnippet);
     }
@@ -531,13 +533,13 @@
          * 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);
             }
             int sideEffectCount = 0;
             assert (sideEffectCount = graph.getNodes().filter(e -> hasSideEffect(e)).count()) >= 0;
-            new ConvertDeoptimizeToGuardPhase().apply(graph);
+            new ConvertDeoptimizeToGuardPhase().apply(graph, null);
             assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node";
 
             switch (frameStateProcessing) {
@@ -666,7 +668,7 @@
          * 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));
@@ -679,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;
                     }
@@ -735,7 +737,7 @@
 
                 afterInlining(graph);
 
-                for (LoopEndNode end : graph.getNodes(LoopEndNode.class)) {
+                for (LoopEndNode end : graph.getNodes(LoopEndNode.TYPE)) {
                     end.disableSafepoint();
                 }
 
@@ -828,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Mar 02 19:11:22 2015 +0100
@@ -45,6 +45,7 @@
 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.*;
@@ -392,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;
         }
 
@@ -721,7 +723,7 @@
 
         assert checkAllVarargPlaceholdersAreDeleted(parameterCount, placeholders);
 
-        new FloatingReadPhase(false, true, false).apply(snippetCopy);
+        new FloatingReadPhase(false, true).apply(snippetCopy);
 
         MemoryAnchorNode memoryAnchor = snippetCopy.add(new MemoryAnchorNode());
         snippetCopy.start().replaceAtUsages(InputType.Memory, memoryAnchor);
@@ -736,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) {
@@ -746,7 +748,7 @@
             List<MemoryMapNode> memMaps = returnNodes.stream().map(n -> n.getMemoryMap()).collect(Collectors.toList());
             ValueNode returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
             this.returnNode = snippet.add(new ReturnNode(returnValue));
-            MemoryMapImpl mmap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps, false);
+            MemoryMapImpl mmap = FloatingReadPhase.mergeMemoryMaps(merge, memMaps);
             MemoryMapNode memoryMap = snippet.unique(new MemoryMapNode(mmap.getMap()));
             this.returnNode.setMemoryMap(memoryMap);
             for (MemoryMapNode mm : memMaps) {
@@ -1219,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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Mon Mar 02 19:11:22 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;
 
@@ -50,9 +51,12 @@
     /** Length of both arrays. */
     @Input ValueNode length;
 
+    @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
+
     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();
@@ -137,4 +141,13 @@
     public LocationIdentity getLocationIdentity() {
         return NamedLocationIdentity.getArrayLocation(kind);
     }
+
+    public MemoryNode getLastLocationAccess() {
+        return lastLocationAccess;
+    }
+
+    public void setLastLocationAccess(MemoryNode lla) {
+        updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla));
+        lastLocationAccess = lla;
+    }
 }
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/AssertionNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicArrayCopyNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BasicObjectCloneNode.java	Mon Mar 02 19:11:22 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
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitCountNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanForwardNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/BitScanReverseNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DeferredPiNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectObjectStoreNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectReadNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/DirectStoreNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ExplodeLoopNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/LoadSnippetVarargParameterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java	Mon Mar 02 19:11:22 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();
@@ -170,7 +171,7 @@
             InliningUtil.inline(invoke, replacementGraph, false, null);
             Debug.dump(graph(), "After inlining replacement %s", replacementGraph);
         } else {
-            if (stateAfter() == null) {
+            if (invoke.stateAfter() == null) {
                 throw new GraalInternalError("cannot lower to invoke without state: %s", this);
             }
             invoke.lower(tool);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroStateSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathIntrinsicNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MathPowNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MemoryAnchorNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/PureFunctionMacroNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReadRegisterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ReverseBytesNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/WriteRegisterNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.runtime/src/com/oracle/graal/runtime/RuntimeProvider.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java	Mon Mar 02 19:11:22 2015 +0100
@@ -98,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();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/BytecodeInterpreterPartialEvaluationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -0,0 +1,320 @@
+/*
+ * 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.truffle.api.*;
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.api.frame.*;
+import com.oracle.truffle.api.nodes.*;
+
+public class BytecodeInterpreterPartialEvaluationTest extends PartialEvaluationTest {
+
+    public static class Bytecode {
+        public static final byte CONST = 0;
+        public static final byte RETURN = 1;
+        public static final byte ADD = 2;
+        public static final byte IFZERO = 3;
+        public static final byte POP = 4;
+        public static final byte JMP = 5;
+        public static final byte DUP = 6;
+    }
+
+    public static boolean TRACE = false;
+
+    public static class Program extends RootNode {
+        private final String name;
+        @CompilationFinal private final byte[] bytecodes;
+        @CompilationFinal private final FrameSlot[] locals;
+        @CompilationFinal private final FrameSlot[] stack;
+
+        public Program(String name, byte[] bytecodes, int maxLocals, int maxStack) {
+            this.name = name;
+            this.bytecodes = bytecodes;
+            locals = new FrameSlot[maxLocals];
+            stack = new FrameSlot[maxStack];
+            for (int i = 0; i < maxLocals; ++i) {
+                locals[i] = this.getFrameDescriptor().addFrameSlot("local" + i);
+                locals[i].setKind(FrameSlotKind.Int);
+            }
+            for (int i = 0; i < maxStack; ++i) {
+                stack[i] = this.getFrameDescriptor().addFrameSlot("stack" + i);
+                stack[i].setKind(FrameSlotKind.Int);
+            }
+        }
+
+        protected void setInt(VirtualFrame frame, int stackIndex, int value) {
+            frame.setInt(stack[stackIndex], value);
+        }
+
+        protected int getInt(VirtualFrame frame, int stackIndex) {
+            try {
+                return frame.getInt(stack[stackIndex]);
+            } catch (FrameSlotTypeException e) {
+                throw new IllegalStateException("Error accessing stack slot " + stackIndex);
+            }
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+
+        public void trace(String format, Object... args) {
+            if (CompilerDirectives.inInterpreter() && TRACE) {
+                System.out.println(String.format(format, args));
+            }
+        }
+
+        @Override
+        @ExplodeLoop(merge = true)
+        public Object execute(VirtualFrame frame) {
+            trace("Start program");
+            int topOfStack = -1;
+            int bci = 0;
+            while (true) {
+                CompilerAsserts.partialEvaluationConstant(bci);
+                byte bc = bytecodes[bci];
+                byte value = 0;
+                switch (bc) {
+                    case Bytecode.CONST:
+                        value = bytecodes[bci + 1];
+                        trace("%d (%d): CONST %s", bci, topOfStack, value);
+                        setInt(frame, ++topOfStack, value);
+                        bci = bci + 2;
+                        continue;
+
+                    case Bytecode.RETURN:
+                        trace("%d (%d): RETURN", bci, topOfStack);
+                        return getInt(frame, topOfStack);
+
+                    case Bytecode.ADD: {
+                        int left = getInt(frame, topOfStack);
+                        int right = getInt(frame, topOfStack - 1);
+                        trace("%d (%d): ADD %d %d", bci, topOfStack, left, right);
+                        setInt(frame, topOfStack - 1, left + right);
+                        topOfStack--;
+                        bci = bci + 1;
+                        continue;
+                    }
+
+                    case Bytecode.IFZERO:
+                        trace("%d (%d): IFZERO", bci, topOfStack);
+                        if (getInt(frame, topOfStack--) == 0) {
+                            bci = bytecodes[bci + 1];
+                            continue;
+                        } else {
+                            bci = bci + 2;
+                            continue;
+                        }
+
+                    case Bytecode.POP:
+                        trace("%d (%d): POP", bci, topOfStack);
+                        topOfStack--;
+                        bci++;
+                        continue;
+
+                    case Bytecode.JMP:
+                        trace("%d (%d): JMP", bci, topOfStack);
+                        bci = bytecodes[bci + 1];
+                        continue;
+
+                    case Bytecode.DUP:
+                        trace("%d (%d): DUP", bci, topOfStack);
+                        setInt(frame, topOfStack + 1, getInt(frame, topOfStack));
+                        topOfStack++;
+                        bci++;
+                        continue;
+                }
+            }
+        }
+    }
+
+    public static Object constant42() {
+        return 42;
+    }
+
+    private static void assertReturns42(Program program) {
+        Assert.assertEquals(Integer.valueOf(42), Truffle.getRuntime().createCallTarget(program).call());
+    }
+
+    private void assertPartialEvalEqualsAndRunsCorrect(Program program) {
+        assertReturns42(program);
+        assertPartialEvalEquals("constant42", program);
+    }
+
+    @Test
+    public void constReturnProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */42,
+        /* 2: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("constReturnProgram", bytecodes, 0, 2));
+    }
+
+    @Test
+    public void constAddProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */40,
+        /* 2: */Bytecode.CONST,
+        /* 3: */2,
+        /* 4: */Bytecode.ADD,
+        /* 5: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("constAddProgram", bytecodes, 0, 2));
+    }
+
+    @Test
+    public void simpleIfProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */40,
+        /* 2: */Bytecode.CONST,
+        /* 3: */1,
+        /* 4: */Bytecode.IFZERO,
+        /* 5: */8,
+        /* 6: */Bytecode.CONST,
+        /* 7: */42,
+        /* 8: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("simpleIfProgram", bytecodes, 0, 3));
+    }
+
+    @Test
+    public void ifAndPopProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */40,
+        /* 2: */Bytecode.CONST,
+        /* 3: */1,
+        /* 4: */Bytecode.IFZERO,
+        /* 5: */9,
+        /* 6: */Bytecode.POP,
+        /* 7: */Bytecode.CONST,
+        /* 8: */42,
+        /* 9: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("ifAndPopProgram", bytecodes, 0, 3));
+    }
+
+    @Test
+    public void simpleLoopProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */42,
+        /* 2: */Bytecode.CONST,
+        /* 3: */-12,
+        /* 4: */Bytecode.CONST,
+        /* 5: */1,
+        /* 6: */Bytecode.ADD,
+        /* 7: */Bytecode.DUP,
+        /* 8: */Bytecode.IFZERO,
+        /* 9: */12,
+        /* 10: */Bytecode.JMP,
+        /* 11: */4,
+        /* 12: */Bytecode.POP,
+        /* 13: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("simpleLoopProgram", bytecodes, 0, 3));
+    }
+
+    @Test
+    public void nestedLoopsProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */42,
+        /* 2: */Bytecode.CONST,
+        /* 3: */-2,
+        /* 4: */Bytecode.CONST,
+        /* 5: */1,
+        /* 6: */Bytecode.ADD,
+        /* 7: */Bytecode.DUP,
+        /* 8: */Bytecode.CONST,
+        /* 9: */-2,
+        /* 10: */Bytecode.CONST,
+        /* 11: */1,
+        /* 12: */Bytecode.ADD,
+        /* 13: */Bytecode.DUP,
+        /* 14: */Bytecode.IFZERO,
+        /* 15: */18,
+        /* 16: */Bytecode.JMP,
+        /* 17: */10,
+        /* 18: */Bytecode.POP,
+        /* 19: */Bytecode.IFZERO,
+        /* 20: */23,
+        /* 21: */Bytecode.JMP,
+        /* 22: */4,
+        /* 23: */Bytecode.POP,
+        /* 24: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("nestedLoopsProgram", bytecodes, 0, 6));
+    }
+
+    @Test(timeout = 1000)
+    public void manyIfsProgram() {
+        byte[] bytecodes = new byte[]{
+        /* 0: */Bytecode.CONST,
+        /* 1: */40,
+        /* 2: */Bytecode.CONST,
+        /* 3: */1,
+        /* 4: */Bytecode.IFZERO,
+        /* 5: */8,
+        /* 6: */Bytecode.CONST,
+        /* 7: */1,
+        /* 8: */Bytecode.IFZERO,
+        /* 9: */12,
+        /* 10: */Bytecode.CONST,
+        /* 11: */1,
+        /* 12: */Bytecode.IFZERO,
+        /* 13: */16,
+        /* 14: */Bytecode.CONST,
+        /* 15: */1,
+        /* 16: */Bytecode.IFZERO,
+        /* 17: */20,
+        /* 18: */Bytecode.CONST,
+        /* 19: */1,
+        /* 20: */Bytecode.IFZERO,
+        /* 21: */24,
+        /* 22: */Bytecode.CONST,
+        /* 23: */1,
+        /* 24: */Bytecode.IFZERO,
+        /* 25: */28,
+        /* 26: */Bytecode.CONST,
+        /* 27: */1,
+        /* 28: */Bytecode.IFZERO,
+        /* 29: */32,
+        /* 30: */Bytecode.CONST,
+        /* 31: */1,
+        /* 32: */Bytecode.IFZERO,
+        /* 33: */36,
+        /* 34: */Bytecode.CONST,
+        /* 35: */1,
+        /* 36: */Bytecode.IFZERO,
+        /* 37: */40,
+        /* 38: */Bytecode.CONST,
+        /* 39: */1,
+        /* 40: */Bytecode.IFZERO,
+        /* 41: */44,
+        /* 42: */Bytecode.CONST,
+        /* 43: */42,
+        /* 44: */Bytecode.RETURN};
+        assertPartialEvalEqualsAndRunsCorrect(new Program("manyIfsProgram", bytecodes, 0, 3));
+    }
+}
--- /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	Mon Mar 02 19:11:22 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]);
+    }
+}
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/InstrumentationPartialEvaluationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -25,9 +25,11 @@
 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
@@ -48,7 +50,6 @@
         assertPartialEvalEquals("constant42", root);
     }
 
-    @Ignore
     @Test
     public void constantValueProbedNoInstruments() {
         FrameDescriptor fd = new FrameDescriptor();
@@ -59,7 +60,6 @@
         assertPartialEvalEquals("constant42", root);
     }
 
-    @Ignore
     @Test
     public void constantValueProbedNullInstrument() {
         FrameDescriptor fd = new FrameDescriptor();
@@ -72,7 +72,6 @@
         assertPartialEvalEquals("constant42", root);
     }
 
-    @Ignore
     @Test
     public void constantValueProbedNullInstrumentDisposed() {
         FrameDescriptor fd = new FrameDescriptor();
@@ -86,7 +85,6 @@
         assertPartialEvalEquals("constant42", root);
     }
 
-    @Ignore
     @Test
     public void constantValueProbedTwoNullInstruments() {
         FrameDescriptor fd = new FrameDescriptor();
@@ -101,7 +99,6 @@
         assertPartialEvalEquals("constant42", root);
     }
 
-    @Ignore
     @Test
     public void constantValueProbedThreeNullInstruments() {
         FrameDescriptor fd = new FrameDescriptor();
@@ -118,7 +115,6 @@
         assertPartialEvalEquals("constant42", root);
     }
 
-    @Ignore
     @Test
     public void constantValueProbedThreeNullInstrumentsOneDisposed() {
         FrameDescriptor fd = new FrameDescriptor();
@@ -135,4 +131,118 @@
         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.
+        final ASTProber prober = 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;
+                    }
+
+                });
+            }
+        };
+        Probe.registerASTProber(prober);
+        try {
+            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
+        } finally {
+            Probe.unregisterASTProber(prober);
+        }
+
+    }
+
+    /**
+     * Experimental feature; not yet validated.
+     */
+    @Test
+    public void specialOptInstrument() {
+        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.
+        final ASTProber prober = 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;
+                    }
+                });
+            }
+        };
+        Probe.registerASTProber(prober);
+        try {
+            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
+
+            final boolean[] isCurrentlyCompiled = {false};
+            final Instrument optInstrument = Instrument.create(new Instrument.TruffleOptListener() {
+
+                public void notifyIsCompiled(boolean isCompiled) {
+                    isCurrentlyCompiled[0] = isCompiled;
+                }
+            });
+            probe[0].attach(optInstrument);
+
+            Assert.assertEquals(42, callTarget.call()); // Correct result
+            Assert.assertFalse(isCurrentlyCompiled[0]);
+
+            // TODO (mlvdv) compile, call again, and assert that isCurrentlyCompiled == true
+
+        } finally {
+            Probe.unregisterASTProber(prober);
+        }
+
+    }
 }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -77,7 +77,7 @@
         final OptimizedCallTarget compilable = (OptimizedCallTarget) Truffle.getRuntime().createCallTarget(root);
         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);
         }
     }
@@ -89,14 +89,14 @@
         compilable.call(arguments);
 
         try (Scope s = Debug.scope("TruffleCompilation", new TruffleDebugJavaMethod(compilable))) {
-            return truffleCompiler.getPartialEvaluator().createGraph(compilable, allowAssumptions, null);
+            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();
         }
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/BlockTestNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/nodes/RootTestNode.java	Mon Mar 02 19:11:22 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/src/com/oracle/graal/truffle/FrameWithBoxing.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/FrameWithoutBoxing.java	Mon Mar 02 19:11:22 2015 +0100
@@ -41,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;
@@ -67,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() {
@@ -83,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 = getPrimitiveOffset(slot);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Byte.ordinal();
+    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 = getPrimitiveOffset(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 = getPrimitiveOffset(slot);
-        boolean condition = this.getTags()[slot.getIndex()] == FrameSlotKind.Boolean.ordinal();
+    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 = getPrimitiveOffset(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 = getPrimitiveOffset(slot);
-        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 = getPrimitiveOffset(slot);
+    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 = getPrimitiveOffset(slot);
-        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 = getPrimitiveOffset(slot);
+    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 = getPrimitiveOffset(slot);
-        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 = getPrimitiveOffset(slot);
+    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 = getPrimitiveOffset(slot);
-        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 = getPrimitiveOffset(slot);
+    private void setDoubleUnsafe(int slotIndex, FrameSlot slot, double value) {
+        long offset = getPrimitiveOffset(slotIndex);
         unsafePutDouble(getPrimitiveLocals(), offset, value, slot);
     }
 
@@ -241,59 +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 getPrimitiveOffset(FrameSlot slot) {
-        return Unsafe.ARRAY_LONG_BASE_OFFSET + slot.getIndex() * (long) Unsafe.ARRAY_LONG_INDEX_SCALE;
+    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);
         }
     }
 
@@ -321,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"})
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Mon Mar 02 19:11:22 2015 +0100
@@ -113,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
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Mon Mar 02 19:11:22 2015 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.debug.internal.*;
@@ -37,6 +38,8 @@
 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.*;
@@ -97,7 +100,7 @@
         }
     }
 
-    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions, GraphBuilderPlugins graalPlugins) {
+    public StructuredGraph createGraph(final OptimizedCallTarget callTarget, AllowAssumptions allowAssumptions) {
         if (TraceTruffleCompilationHistogram.getValue() || TraceTruffleCompilationDetails.getValue()) {
             constantReceivers = new HashSet<>();
         }
@@ -121,7 +124,7 @@
             HighTierContext tierContext = new HighTierContext(providers, graphCache, new PhaseSuite<HighTierContext>(), OptimisticOptimizations.NONE);
 
             if (TruffleCompilerOptions.FastPE.getValue()) {
-                fastPartialEvaluation(callTarget, graph, baseContext, tierContext, graalPlugins);
+                fastPartialEvaluation(callTarget, graph, baseContext, tierContext);
             } else {
                 createRootGraph(graph);
                 partialEvaluation(callTarget, graph, baseContext, tierContext);
@@ -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,37 +183,102 @@
         }
     }
 
-    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;
         }
 
+        public boolean shouldMergeExplosions(ResolvedJavaMethod method) {
+            ExplodeLoop explodeLoop = method.getAnnotation(ExplodeLoop.class);
+            if (explodeLoop != null) {
+                return explodeLoop.merge();
+            }
+            return false;
+        }
+
     }
 
     @SuppressWarnings("unused")
-    private void fastPartialEvaluation(OptimizedCallTarget callTarget, StructuredGraph graph, PhaseContext baseContext, HighTierContext tierContext, GraphBuilderPlugins graalPlugins) {
+    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 = graalPlugins == null ? new DefaultGraphBuilderPlugins() : graalPlugins.copy();
-        TruffleGraphBuilderPlugins.registerPlugins(providers.getMetaAccess(), plugins);
-        long ms = System.currentTimeMillis();
-        new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), this.snippetReflection, providers.getConstantReflection(), newConfig, plugins,
-                        TruffleCompilerImpl.Optimizations).apply(graph);
-        System.out.println("# ms: " + (System.currentTimeMillis() - ms));
+        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");
 
+        // Perform deoptimize to guard conversion.
+        new ConvertDeoptimizeToGuardPhase().apply(graph, tierContext);
+
+        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);
+                }
+            }
+        }
+
+        // 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)) {
             new PartialEscapePhase(true, canonicalizer).apply(graph, tierContext);
@@ -285,11 +343,11 @@
 
     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);
@@ -301,6 +359,13 @@
                 }
             }
         }
+
+        if (!TruffleCompilerOptions.TruffleInlineAcrossTruffleBoundary.getValue()) {
+            // Do not inline across Truffle boundaries.
+            for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.TYPE)) {
+                mct.invoke().setUseForInlining(false);
+            }
+        }
     }
 
     private void injectConstantCallTarget(final StructuredGraph graph, final OptimizedCallTarget constantCallTarget, PhaseContext baseContext) {
@@ -433,7 +498,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();
@@ -480,7 +545,7 @@
     private void expandDirectCalls(StructuredGraph graph, TruffleExpansionLogger expansionLogger, TruffleInlining inlining, TruffleInliningCache inliningCache) {
         PhaseContext phaseContext = new PhaseContext(providers);
 
-        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.class).snapshot()) {
+        for (MethodCallTargetNode methodCallTargetNode : graph.getNodes(MethodCallTargetNode.TYPE).snapshot()) {
             StructuredGraph inlineGraph = parseDirectCallGraph(phaseContext, graph, inlining, inliningCache, methodCallTargetNode);
 
             if (inlineGraph != null) {
@@ -493,7 +558,7 @@
     }
 
     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;
             }
@@ -508,6 +573,25 @@
             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()) {
@@ -524,25 +608,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, caller, null, decision);
-            } else {
-                graph = inliningCache.getCachedGraph(phaseContext, caller, decision);
-            }
-            decision.getProfile().setGraalDeepNodeCount(graph.getNodeCount());
-
-            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;
+        return decision;
     }
 
     private OptimizedDirectCallNode resolveConstantCallNode(MethodCallTargetNode methodCallTargetNode) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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()));
@@ -147,7 +147,7 @@
             new ReplaceIntrinsicsPhase(providers.getReplacements()).apply(graph);
 
             // Convert deopt to guards.
-            new ConvertDeoptimizeToGuardPhase().apply(graph);
+            new ConvertDeoptimizeToGuardPhase().apply(graph, phaseContext);
 
             PartialEscapePhase partialEscapePhase = new PartialEscapePhase(false, canonicalizer);
 
@@ -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);
                     }
@@ -175,7 +175,7 @@
                 }
 
                 // Convert deopt to guards.
-                new ConvertDeoptimizeToGuardPhase().apply(graph);
+                new ConvertDeoptimizeToGuardPhase().apply(graph, phaseContext);
 
                 new EarlyReadEliminationPhase(canonicalizer).apply(graph, phaseContext);
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerImpl.java	Mon Mar 02 19:11:22 2015 +0100
@@ -43,7 +43,6 @@
 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.*;
 import com.oracle.graal.phases.tiers.*;
@@ -81,14 +80,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));
@@ -120,27 +129,21 @@
         compilationNotify.notifyCompilationStarted(compilable);
 
         try {
-            GraphBuilderSuiteInfo info = createGraphBuilderSuite();
+            PhaseSuite<HighTierContext> graphBuilderSuite = createGraphBuilderSuite();
 
             try (TimerCloseable a = PartialEvaluationTime.start(); Closeable c = PartialEvaluationMemUse.start()) {
-                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES, info.plugins);
+                graph = partialEvaluator.createGraph(compilable, AllowAssumptions.YES);
             }
 
             if (Thread.currentThread().isInterrupted()) {
                 return;
             }
 
-            if (!TruffleCompilerOptions.TruffleInlineAcrossTruffleBoundary.getValue()) {
-                // Do not inline across Truffle boundaries.
-                for (MethodCallTargetNode mct : graph.getNodes(MethodCallTargetNode.class)) {
-                    mct.invoke().setUseForInlining(false);
-                }
-            }
-
             compilationNotify.notifyCompilationTruffleTierFinished(compilable, graph);
-            CompilationResult compilationResult = compileMethodHelper(graph, compilable.toString(), info.suite, 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;
         }
@@ -158,8 +161,8 @@
             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, graphBuilderSuite == null ? createGraphBuilderSuite().suite : graphBuilderSuite,
-                            Optimizations, getProfilingInfo(graph), speculationLog, suites, lirSuites, 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);
         }
@@ -203,24 +206,12 @@
         return result;
     }
 
-    static class GraphBuilderSuiteInfo {
-        final PhaseSuite<HighTierContext> suite;
-        final GraphBuilderPlugins plugins;
-
-        public GraphBuilderSuiteInfo(PhaseSuite<HighTierContext> suite, GraphBuilderPlugins plugins) {
-            this.suite = suite;
-            this.plugins = plugins;
-        }
-    }
-
-    private GraphBuilderSuiteInfo createGraphBuilderSuite() {
+    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();
-        GraphBuilderPlugins plugins = graphBuilderPhase.getGraphBuilderPlugins();
-        iterator.add(new GraphBuilderPhase(config, plugins));
-        return new GraphBuilderSuiteInfo(suite, plugins);
+        iterator.add(new GraphBuilderPhase(config));
+        return suite;
     }
 
     public void processAssumption(Set<Assumption> newAssumptions, Assumption assumption, List<AssumptionValidAssumption> manual) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCompilerOptions.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleExpansionLogger.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInliningProfile.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleReplacements.java	Mon Mar 02 19:11:22 2015 +0100
@@ -50,13 +50,15 @@
     }
 
     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);
-        registerSubstitutions(UnsafeAccessImpl.class, UnsafeAccessSubstitutions.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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/TraceCompilationFailureListener.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/AssumptionNode.java	Mon Mar 02 19:11:22 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,6 +27,7 @@
 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.*;
@@ -38,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;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/BailoutNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/IsCompilationConstantNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerAddExactSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerExactArithmeticSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulExactSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerMulHighNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactSplitNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/UnsignedMulHighNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverInlineMacroNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/asserts/NeverPartOfCompilationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/ForceMaterializeNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/MaterializeFrameNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/frame/NewFrameNode.java	Mon Mar 02 19:11:22 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);
+            }
+            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);
     }
@@ -230,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/CustomizedUnsafeLoadMacroNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeLoadMacroNode.java	Mon Mar 02 19:11:22 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;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/CustomizedUnsafeStoreMacroNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/UnsafeTypeCastMacroNode.java	Mon Mar 02 19:11:22 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;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/VerifyFrameDoesNotEscapePhase.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerAssertsSubstitutions.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/CompilerDirectivesSubstitutions.java	Mon Mar 02 19:11:22 2015 +0100
@@ -73,8 +73,10 @@
     @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);
+    @MethodSubstitution
+    public static boolean isCompilationConstant(Object value) {
+        return IsCompilationConstantNode.check(value);
+    }
 
     @MethodSubstitution
     public static void materialize(Object obj) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/OptimizedCallTargetSubstitutions.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Mon Mar 02 19:11:22 2015 +0100
@@ -26,15 +26,15 @@
 
 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.graph.*;
 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.*;
@@ -47,12 +47,26 @@
 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);
 
-        // OptimizedAssumption.class
+        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) {
@@ -60,25 +74,55 @@
                     Constant constant = arg.asConstant();
                     OptimizedAssumption assumption = builder.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant);
                     builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(assumption.isValid())));
-                    builder.getAssumptions().record(new AssumptionValidAssumption(assumption));
+                    if (assumption.isValid()) {
+                        builder.getAssumptions().record(new AssumptionValidAssumption(assumption));
+                    }
                 } else {
-                    throw new BailoutException("assumption could not be reduced to a constant");
+                    throw builder.bailout("assumption could not be reduced to a constant");
                 }
                 return true;
             }
         });
+    }
 
-        // ExactMath.class
-        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;
-            }
-        });
+    public static void registerExactMathPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
+        Registration r = new Registration(plugins, metaAccess, ExactMath.class);
+        for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) {
+            r.register2("addExact", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                    builder.push(kind.getStackKind(), builder.append(new IntegerAddExactNode(x, y)));
+                    return true;
+                }
+            });
+            r.register2("subtractExact", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                    builder.push(kind.getStackKind(), builder.append(new IntegerSubExactNode(x, y)));
+                    return true;
+                }
+            });
+            r.register2("multiplyExact", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                    builder.push(kind.getStackKind(), builder.append(new IntegerMulExactNode(x, y)));
+                    return true;
+                }
+            });
+            r.register2("multiplyHigh", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                    builder.push(kind.getStackKind(), builder.append(new IntegerMulHighNode(x, y)));
+                    return true;
+                }
+            });
+            r.register2("multiplyHighUnsigned", kind.toJavaClass(), kind.toJavaClass(), new InvocationPlugin() {
+                public boolean apply(GraphBuilderContext builder, ValueNode x, ValueNode y) {
+                    builder.push(kind.getStackKind(), builder.append(new UnsignedMulHighNode(x, y)));
+                    return true;
+                }
+            });
+        }
+    }
 
-        // CompilerDirectives.class
-        r = new Registration(plugins, metaAccess, CompilerDirectives.class);
+    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) {
                 builder.push(Kind.Boolean.getStackKind(), builder.append(ConstantNode.forBoolean(false)));
@@ -122,18 +166,19 @@
         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() {
@@ -143,23 +188,74 @@
             }
         });
 
-        // OptimizedCallTarget.class
-        r = new Registration(plugins, metaAccess, OptimizedCallTarget.class);
+        r = new Registration(plugins, metaAccess, CompilerAsserts.class);
+        r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext builder, ValueNode value) {
+                ValueNode curValue = value;
+                if (curValue instanceof BoxNode) {
+                    BoxNode boxNode = (BoxNode) curValue;
+                    curValue = boxNode.getValue();
+                }
+                if (curValue.isConstant()) {
+                    return true;
+                } else {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append(curValue);
+                    if (curValue instanceof ValuePhiNode) {
+                        ValuePhiNode valuePhi = (ValuePhiNode) curValue;
+                        sb.append(" (");
+                        for (Node n : valuePhi.inputs()) {
+                            sb.append(n);
+                            sb.append("; ");
+                        }
+                        sb.append(")");
+                    }
+                    throw builder.bailout("Partial evaluation did not reduce value to a constant, is a regular compiler node: " + sb.toString());
+                }
+            }
+        });
+    }
+
+    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()) {
@@ -168,7 +264,16 @@
                     if (javaType == null) {
                         builder.push(Kind.Object, object);
                     } else {
-                        Stamp piStamp = StampFactory.declaredTrusted(javaType, nonNull.asJavaConstant().asInt() != 0);
+                        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) {
@@ -189,12 +294,6 @@
                 throw GraalInternalError.shouldNotReachHere("unsafeCast arguments could not reduce to a constant: " + clazz + ", " + nonNull);
             }
         });
-
-        registerUnsafeLoadStorePlugins(r, Kind.Int, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
-
-        // CompilerDirectives.class
-        r = new Registration(plugins, metaAccess, UnsafeAccessImpl.class);
-        registerUnsafeLoadStorePlugins(r, Kind.Boolean, Kind.Byte, Kind.Int, Kind.Short, Kind.Long, Kind.Float, Kind.Double, Kind.Object);
     }
 
     protected static void registerUnsafeLoadStorePlugins(Registration r, Kind... kinds) {
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializedObjectState.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/MaterializedObjectState.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/nodes/VirtualObjectState.java	Mon Mar 02 19:11:22 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/EffectsClosure.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsClosure.java	Mon Mar 02 19:11:22 2015 +0100
@@ -32,6 +32,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
@@ -111,6 +112,12 @@
         };
         ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
         assert VirtualUtil.assertNonReachable(graph, obsoleteNodes);
+        for (Node node : obsoleteNodes) {
+            if (node.isAlive()) {
+                node.replaceAtUsages(null);
+                GraphUtil.killWithUnusedFloatingInputs(node);
+            }
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/GraphEffectList.java	Mon Mar 02 19:11:22 2015 +0100
@@ -130,23 +130,16 @@
      *
      * @param node The fixed node that should be deleted.
      */
-    public void deleteFixedNode(final FixedWithNextNode node) {
+    public void deleteNode(final Node node) {
         add("delete fixed node", (graph, obsoleteNodes) -> {
-            GraphUtil.unlinkFixedNode(node);
-            assert obsoleteNodes.add(node);
+            if (node instanceof FixedWithNextNode) {
+                GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+            }
+            obsoleteNodes.add(node);
         });
     }
 
     /**
-     * Removes the given fixed node from the control flow.
-     *
-     * @param node The fixed node that should be deleted.
-     */
-    public void unlinkFixedNode(final FixedWithNextNode node) {
-        add("unlink fixed node", graph -> GraphUtil.unlinkFixedNode(node));
-    }
-
-    /**
      * Replaces the given node at its usages without deleting it. If the current node is a fixed
      * node it will be disconnected from the control flow, so that it will be deleted by a
      * subsequent {@link DeadCodeEliminationPhase}
@@ -165,11 +158,9 @@
             }
             node.replaceAtUsages(replacement);
             if (node instanceof FixedWithNextNode) {
-                FixedNode next = ((FixedWithNextNode) node).next();
-                ((FixedWithNextNode) node).setNext(null);
-                node.replaceAtPredecessor(next);
-                assert obsoleteNodes.add(node);
+                GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
             }
+            obsoleteNodes.add(node);
         });
     }
 
@@ -181,6 +172,7 @@
      * @param newInput The value to replace with.
      */
     public void replaceFirstInput(final Node node, final Node oldInput, final Node newInput) {
+        assert node.isAlive() && oldInput.isAlive() && !newInput.isDeleted();
         add("replace first input", new Effect() {
             @Override
             public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
@@ -194,13 +186,4 @@
             }
         });
     }
-
-    /**
-     * Performs a custom action.
-     *
-     * @param action The action that should be performed when the effects are applied.
-     */
-    public void customAction(final Runnable action) {
-        add("customAction", graph -> action.run());
-    }
 }
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PEReadEliminationClosure.java	Mon Mar 02 19:11:22 2015 +0100
@@ -94,7 +94,7 @@
             ValueNode value = getScalarAlias(store.value());
             boolean result = false;
             if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                effects.deleteFixedNode(store);
+                effects.deleteNode(store);
                 result = true;
             }
             state.killReadCache(store.field());
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeBlockState.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeClosure.java	Mon Mar 02 19:11:22 2015 +0100
@@ -224,7 +224,7 @@
         }
     }
 
-    private static void updateStatesForMaterialized(PartialEscapeBlockState<?> state, ObjectState obj) {
+    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()) {
@@ -649,6 +649,7 @@
                 if (uniqueVirtualObject) {
                     // all inputs refer to the same object: just make the phi node an alias
                     addAndMarkAlias(objStates[0].virtual, phi);
+                    mergeEffects.deleteNode(phi);
                     return false;
                 } else {
                     // all inputs are virtual: check if they're compatible and without identity
@@ -680,6 +681,7 @@
                     if (compatible) {
                         VirtualObjectNode virtual = getValueObjectVirtual(phi, getObjectState(states.get(0), phi.valueAt(0)).virtual);
                         mergeEffects.addFloatingNode(virtual, "valueObjectNode");
+                        mergeEffects.deleteNode(phi);
 
                         boolean materialized = mergeObjectStates(virtual, objStates, states);
                         addAndMarkAlias(virtual, virtual);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/ReadEliminationClosure.java	Mon Mar 02 19:11:22 2015 +0100
@@ -75,7 +75,7 @@
                     StoreFieldNode store = (StoreFieldNode) node;
                     ValueNode value = getScalarAlias(store.value());
                     if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                        effects.deleteFixedNode(store);
+                        effects.deleteNode(store);
                         deleted = true;
                     }
                     state.killReadCache(store.field());
@@ -108,7 +108,7 @@
 
                 ValueNode value = getScalarAlias(write.value());
                 if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                    effects.deleteFixedNode(write);
+                    effects.deleteNode(write);
                     deleted = true;
                 }
                 processIdentity(state, write.location().getLocationIdentity());
@@ -141,7 +141,7 @@
 
                     ValueNode value = getScalarAlias(write.value());
                     if (GraphUtil.unproxify(value) == GraphUtil.unproxify(cachedValue)) {
-                        effects.deleteFixedNode(write);
+                        effects.deleteNode(write);
                         deleted = true;
                     }
                     processIdentity(state, write.getLocationIdentity());
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualUtil.java	Mon Mar 02 19:11:22 2015 +0100
@@ -62,7 +62,7 @@
         }
 
         for (Node node : obsoleteNodes) {
-            if (node instanceof FixedNode) {
+            if (node instanceof FixedNode && !node.isDeleted()) {
                 assert !flood.isMarked(node) : node;
             }
         }
@@ -87,7 +87,7 @@
         }
         boolean success = true;
         for (Node node : obsoleteNodes) {
-            if (flood.isMarked(node)) {
+            if (!node.isDeleted() && flood.isMarked(node)) {
                 TTY.println("offending node path:");
                 Node current = node;
                 TTY.print(current.toString());
@@ -109,12 +109,24 @@
         return success;
     }
 
-    public static void trace(String format, Object... obj) {
-        if (TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+    public static void trace(String format, Object obj) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
             Debug.logv(format, obj);
         }
     }
 
+    public static void trace(String format, Object obj, Object obj2) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2);
+        }
+    }
+
+    public static void trace(String format, Object obj, Object obj2, Object obj3) {
+        if (Debug.isEnabled() && TraceEscapeAnalysis.getValue() && Debug.isLogEnabled()) {
+            Debug.logv(format, obj, obj2, obj3);
+        }
+    }
+
     public static boolean matches(StructuredGraph graph, String filter) {
         if (filter != null) {
             return matchesHelper(graph, filter);
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/VirtualizerToolImpl.java	Mon Mar 02 19:11:22 2015 +0100
@@ -117,9 +117,7 @@
     @Override
     public void replaceWithVirtual(VirtualObjectNode virtual) {
         closure.addAndMarkAlias(virtual, current);
-        if (current instanceof FixedWithNextNode) {
-            effects.deleteFixedNode((FixedWithNextNode) current);
-        }
+        effects.deleteNode(current);
         deleted = true;
     }
 
@@ -132,7 +130,7 @@
 
     @Override
     public void delete() {
-        effects.deleteFixedNode((FixedWithNextNode) current);
+        effects.deleteNode(current);
         deleted = true;
     }
 
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Signed.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/Unsigned.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/SnippetLocationNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Mon Mar 02 19:11:22 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;
     }
 
--- a/graal/com.oracle.nfi/src/com/oracle/nfi/api/NativeFunctionPointer.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.nfi/src/com/oracle/nfi/api/NativeFunctionPointer.java	Mon Mar 02 19:11:22 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/src/com/oracle/truffle/api/dsl/Implies.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/Implies.java	Mon Mar 02 19:11:22 2015 +0100
@@ -28,7 +28,7 @@
 
 /**
  * Experimental API.
- * 
+ *
  * @deprecated annotation has no effect anymore.
  */
 @Retention(RetentionPolicy.CLASS)
--- a/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystem.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/TypeSystemReference.java	Mon Mar 02 19:11:22 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.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ReplaceTest.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/instrument/InstrumentationTest.java	Mon Mar 02 19:11:22 2015 +0100
@@ -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
@@ -591,12 +591,12 @@
             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");
@@ -695,7 +695,7 @@
             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/src/com/oracle/truffle/api/CompilerAsserts.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerAsserts.java	Mon Mar 02 19:11:22 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,38 @@
      * 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;
+    public static <T> void compilationConstant(Object value) {
+        if (!CompilerDirectives.isCompilationConstant(value)) {
+            neverPartOfCompilation("Value is not compilation constant");
+        }
     }
 
     /**
-     * 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.
+     * Assertion that the corresponding value is reduced to a constant during the initial partial
+     * evaluation phase.
      *
      * @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 partialEvaluationConstant(Object value) {
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/CompilerDirectives.java	Mon Mar 02 19:11:22 2015 +0100
@@ -80,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();
     }
 
     /**
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameSlotKind.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/frame/FrameUtil.java	Mon Mar 02 19:11:22 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/instrument/Instrument.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Instrument.java	Mon Mar 02 19:11:22 2015 +0100
@@ -24,13 +24,15 @@
  */
 package com.oracle.truffle.api.instrument;
 
+import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
-import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.instrument.impl.*;
 import com.oracle.truffle.api.nodes.*;
 
 // TODO (mlvdv) migrate some of this to external documentation.
+// TODO (mlvdv) move all this to a factory implemented in .impl (together with Probe),
+// then break out some of the nested classes into package privates.
 /**
  * A dynamically added/removed binding between a {@link Probe}, which provides notification of
  * {@linkplain TruffleEventListener execution events} taking place at a {@link Node} in a Guest
@@ -44,8 +46,8 @@
  * <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 listener.</li>
- * <li>When no longer needed, "detach" the Instrument via {@link Instrument#dispose()}, at which
- * point event notifications to the listener cease, and the Instrument becomes unusable.</li>
+ * <li>When no longer needed, "detach" the Instrument via {@link TruffleEventInstrument#dispose()},
+ * at which point event notifications to the listener cease, and the Instrument becomes unusable.</li>
  * </ol>
  * <p>
  * <h4>Options for creating listeners:</h4>
@@ -123,8 +125,8 @@
  * error to attempt attaching a previously attached instrument.</li>
  * <li>Attaching an instrument modifies every existing clone of the AST to which it is being
  * attached, which can trigger deoptimization.</li>
- * <li>The method {@link Instrument#dispose()} makes an instrument inactive by removing it from the
- * Probe to which it was attached and rendering it permanently inert.</li>
+ * <li>The method {@link TruffleEventInstrument#dispose()} makes an instrument inactive by removing
+ * it from the Probe to which it was attached and rendering it permanently inert.</li>
  * <li>Disposal removes the implementation of an instrument from all ASTs to which it was attached,
  * which can trigger deoptimization.</li>
  * </ul>
@@ -142,7 +144,7 @@
  * @see Probe
  * @see TruffleEventListener
  */
-public final class Instrument {
+public abstract class Instrument {
 
     /**
      * Creates an instrument that will route execution events to a listener.
@@ -152,25 +154,23 @@
      * @return a new instrument, ready for attachment at a probe
      */
     public static Instrument create(TruffleEventListener listener, String instrumentInfo) {
-        return new Instrument(listener, instrumentInfo);
+        return new TruffleEventInstrument(listener, instrumentInfo);
     }
 
     /**
      * Creates an instrument that will route execution events to a listener.
      */
     public static Instrument create(TruffleEventListener listener) {
-        return new Instrument(listener, null);
+        return new TruffleEventInstrument(listener, null);
     }
 
+    // TODO (mlvdv) experimental
     /**
-     * Tool-supplied listener for events.
+     * For implementation testing.
      */
-    private final TruffleEventListener toolEventListener;
-
-    /**
-     * Optional documentation, mainly for debugging.
-     */
-    private final String instrumentInfo;
+    public static Instrument create(TruffleOptListener listener) {
+        return new TruffleOptInstrument(listener, null);
+    }
 
     /**
      * Has this instrument been disposed? stays true once set.
@@ -179,8 +179,12 @@
 
     private Probe probe = null;
 
-    private Instrument(TruffleEventListener listener, String instrumentInfo) {
-        this.toolEventListener = listener;
+    /**
+     * Optional documentation, mainly for debugging.
+     */
+    private final String instrumentInfo;
+
+    private Instrument(String instrumentInfo) {
         this.instrumentInfo = instrumentInfo;
     }
 
@@ -216,35 +220,176 @@
         return isDisposed;
     }
 
-    InstrumentNode addToChain(InstrumentNode nextNode) {
-        return new InstrumentNode(nextNode);
-    }
+    abstract InstrumentNode addToChain(InstrumentNode nextNode);
 
     /**
      * Removes this instrument from an instrument chain.
      */
-    InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
-        boolean found = false;
-        if (instrumentNode != null) {
-            if (instrumentNode.getInstrument() == this) {
-                // Found the match at the head of the chain
-                return instrumentNode.nextInstrument;
+    abstract InstrumentNode removeFromChain(InstrumentNode instrumentNode);
+
+    private static final class TruffleEventInstrument extends Instrument {
+
+        /**
+         * Tool-supplied listener for events.
+         */
+        private final TruffleEventListener toolEventListener;
+
+        private TruffleEventInstrument(TruffleEventListener listener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.toolEventListener = listener;
+        }
+
+        @Override
+        InstrumentNode addToChain(InstrumentNode nextNode) {
+            return new TruffleEventInstrumentNode(nextNode);
+        }
+
+        @Override
+        InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrument;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(TruffleEventInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
+        }
+
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class TruffleEventInstrumentNode extends InstrumentNode {
+
+            private TruffleEventInstrumentNode(InstrumentNode nextNode) {
+                super(nextNode);
+            }
+
+            public void enter(Node node, VirtualFrame vFrame) {
+                TruffleEventInstrument.this.toolEventListener.enter(node, vFrame);
+                if (nextInstrument != null) {
+                    nextInstrument.enter(node, vFrame);
+                }
+            }
+
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                TruffleEventInstrument.this.toolEventListener.returnVoid(node, vFrame);
+                if (nextInstrument != null) {
+                    nextInstrument.returnVoid(node, vFrame);
+                }
+            }
+
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                TruffleEventInstrument.this.toolEventListener.returnValue(node, vFrame, result);
+                if (nextInstrument != null) {
+                    nextInstrument.returnValue(node, vFrame, result);
+                }
+            }
+
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                TruffleEventInstrument.this.toolEventListener.returnExceptional(node, vFrame, exception);
+                if (nextInstrument != null) {
+                    nextInstrument.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : toolEventListener.getClass().getSimpleName();
             }
-            // Match not at the head of the chain; remove it.
-            found = instrumentNode.removeFromChain(Instrument.this);
+        }
+
+    }
+
+    public interface TruffleOptListener {
+        void notifyIsCompiled(boolean isCompiled);
+    }
+
+    private static final class TruffleOptInstrument extends Instrument {
+
+        private final TruffleOptListener toolOptListener;
+
+        private TruffleOptInstrument(TruffleOptListener listener, String instrumentInfo) {
+            super(instrumentInfo);
+            this.toolOptListener = listener;
+        }
+
+        @Override
+        InstrumentNode addToChain(InstrumentNode nextNode) {
+            return new TruffleOptInstrumentNode(nextNode);
+        }
+
+        @Override
+        InstrumentNode removeFromChain(InstrumentNode instrumentNode) {
+            boolean found = false;
+            if (instrumentNode != null) {
+                if (instrumentNode.getInstrument() == this) {
+                    // Found the match at the head of the chain
+                    return instrumentNode.nextInstrument;
+                }
+                // Match not at the head of the chain; remove it.
+                found = instrumentNode.removeFromChain(TruffleOptInstrument.this);
+            }
+            if (!found) {
+                throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+            }
+            return instrumentNode;
         }
-        if (!found) {
-            throw new IllegalStateException("Couldn't find instrument node to remove: " + this);
+
+        @NodeInfo(cost = NodeCost.NONE)
+        private final class TruffleOptInstrumentNode extends InstrumentNode {
+
+            private boolean isCompiled;
+
+            private TruffleOptInstrumentNode(InstrumentNode nextNode) {
+                super(nextNode);
+                this.isCompiled = CompilerDirectives.inCompiledCode();
+            }
+
+            public void enter(Node node, VirtualFrame vFrame) {
+                if (this.isCompiled != CompilerDirectives.inCompiledCode()) {
+                    this.isCompiled = CompilerDirectives.inCompiledCode();
+                    TruffleOptInstrument.this.toolOptListener.notifyIsCompiled(this.isCompiled);
+                }
+                if (nextInstrument != null) {
+                    nextInstrument.enter(node, vFrame);
+                }
+            }
+
+            public void returnVoid(Node node, VirtualFrame vFrame) {
+                if (nextInstrument != null) {
+                    nextInstrument.returnVoid(node, vFrame);
+                }
+            }
+
+            public void returnValue(Node node, VirtualFrame vFrame, Object result) {
+                if (nextInstrument != null) {
+                    nextInstrument.returnValue(node, vFrame, result);
+                }
+            }
+
+            public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
+                if (nextInstrument != null) {
+                    nextInstrument.returnExceptional(node, vFrame, exception);
+                }
+            }
+
+            public String instrumentationInfo() {
+                final String info = getInstrumentInfo();
+                return info != null ? info : toolOptListener.getClass().getSimpleName();
+            }
         }
-        return instrumentNode;
+
     }
 
     @NodeInfo(cost = NodeCost.NONE)
-    final class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
+    abstract class InstrumentNode extends Node implements TruffleEventListener, InstrumentationNode {
+        @Child protected InstrumentNode nextInstrument;
 
-        @Child private InstrumentNode nextInstrument;
-
-        private InstrumentNode(InstrumentNode nextNode) {
+        protected InstrumentNode(InstrumentNode nextNode) {
             this.nextInstrument = nextNode;
         }
 
@@ -286,40 +431,10 @@
             return nextInstrument.removeFromChain(instrument);
         }
 
-        public void enter(Node node, VirtualFrame frame) {
-            Instrument.this.toolEventListener.enter(node, frame);
-            if (nextInstrument != null) {
-                nextInstrument.enter(node, frame);
-            }
-        }
-
-        public void returnVoid(Node node, VirtualFrame frame) {
-            Instrument.this.toolEventListener.returnVoid(node, frame);
-            if (nextInstrument != null) {
-                nextInstrument.returnVoid(node, frame);
-            }
+        protected String getInstrumentInfo() {
+            return Instrument.this.instrumentInfo;
         }
 
-        public void returnValue(Node node, VirtualFrame frame, Object result) {
-            Instrument.this.toolEventListener.returnValue(node, frame, result);
-            if (nextInstrument != null) {
-                nextInstrument.returnValue(node, frame, result);
-            }
-        }
-
-        public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
-            Instrument.this.toolEventListener.returnExceptional(node, frame, exception);
-            if (nextInstrument != null) {
-                nextInstrument.returnExceptional(node, frame, exception);
-            }
-        }
-
-        public String instrumentationInfo() {
-            if (Instrument.this.instrumentInfo != null) {
-                return Instrument.this.instrumentInfo;
-            }
-            return toolEventListener.getClass().getSimpleName();
-        }
     }
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/Probe.java	Mon Mar 02 19:11:22 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.*;
@@ -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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/ProbeNode.java	Mon Mar 02 19:11:22 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.*;
@@ -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,43 +216,41 @@
             }
         }
 
-        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";
         }
-
     }
 
     /**
@@ -305,20 +284,20 @@
             throw new IllegalStateException("Instruments may not be removed at a \"lite-probed\" location");
         }
 
-        public void enter(Node node, VirtualFrame frame) {
-            eventListener.enter(node, frame);
+        public void enter(Node node, VirtualFrame vFrame) {
+            eventListener.enter(node, vFrame);
         }
 
-        public void returnVoid(Node node, VirtualFrame frame) {
-            eventListener.returnVoid(node, frame);
+        public void returnVoid(Node node, VirtualFrame vFrame) {
+            eventListener.returnVoid(node, vFrame);
         }
 
-        public void returnValue(Node node, VirtualFrame frame, Object result) {
-            eventListener.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) {
-            eventListener.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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/StandardSyntaxTag.java	Mon Mar 02 19:11:22 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 {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/TruffleEventListener.java	Mon Mar 02 19:11:22 2015 +0100
@@ -36,22 +36,22 @@
     /**
      * Receive notification that an AST node's execute method is about to be called.
      */
-    void enter(Node node, VirtualFrame frame);
+    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 frame);
+    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 frame, Object result);
+    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 frame, Exception exception);
+    void returnExceptional(Node node, VirtualFrame vFrame, Exception exception);
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultEventListener.java	Mon Mar 02 19:11:22 2015 +0100
@@ -34,16 +34,16 @@
  */
 public class DefaultEventListener implements TruffleEventListener {
 
-    public void enter(Node node, VirtualFrame frame) {
+    public void enter(Node node, VirtualFrame vFrame) {
     }
 
-    public void returnVoid(Node node, VirtualFrame frame) {
+    public void returnVoid(Node node, VirtualFrame vFrame) {
     }
 
-    public void returnValue(Node node, VirtualFrame frame, Object result) {
+    public void returnValue(Node node, VirtualFrame vFrame, Object result) {
     }
 
-    public void returnExceptional(Node node, VirtualFrame frame, Exception exception) {
+    public void returnExceptional(Node node, VirtualFrame vFrame, Exception exception) {
     }
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/SimpleEventListener.java	Mon Mar 02 19:11:22 2015 +0100
@@ -38,7 +38,7 @@
  */
 public abstract class SimpleEventListener implements TruffleEventListener {
 
-    public void enter(Node node, VirtualFrame frame) {
+    public void enter(Node node, VirtualFrame vFrame) {
     }
 
     /**
@@ -46,21 +46,21 @@
      * means: with or without a return value (ignored) or via exception (ignored).
      *
      * @param node
-     * @param frame
+     * @param vFrame
      */
-    public void returnAny(Node node, VirtualFrame frame) {
+    public void returnAny(Node node, VirtualFrame vFrame) {
     }
 
-    public final void returnVoid(Node node, VirtualFrame frame) {
-        returnAny(node, frame);
+    public final void returnVoid(Node node, VirtualFrame vFrame) {
+        returnAny(node, vFrame);
     }
 
-    public final void returnValue(Node node, VirtualFrame frame, Object result) {
-        returnAny(node, frame);
+    public final void returnValue(Node node, VirtualFrame vFrame, Object result) {
+        returnAny(node, vFrame);
     }
 
-    public final void returnExceptional(Node node, VirtualFrame frame, Exception e) {
-        returnAny(node, frame);
+    public final void returnExceptional(Node node, VirtualFrame vFrame, Exception e) {
+        returnAny(node, vFrame);
     }
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ExplodeLoop.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/ExplodeLoop.java	Mon Mar 02 19:11:22 2015 +0100
@@ -33,4 +33,5 @@
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface ExplodeLoop {
+    boolean merge() default false;
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Mar 02 19:11:22 2015 +0100
@@ -41,7 +41,6 @@
 public abstract class Node implements NodeInterface, Cloneable {
 
     @CompilationFinal private Node parent;
-
     @CompilationFinal private SourceSection sourceSection;
 
     /**
@@ -573,11 +572,7 @@
 
     public final void atomic(Runnable closure) {
         RootNode rootNode = getRootNode();
-        if (rootNode != null) {
-            synchronized (rootNode) {
-                closure.run();
-            }
-        } else {
+        synchronized (rootNode != null ? rootNode : GIL) {
             closure.run();
         }
     }
@@ -585,14 +580,10 @@
     public final <T> T atomic(Callable<T> closure) {
         try {
             RootNode rootNode = getRootNode();
-            if (rootNode != null) {
-                synchronized (rootNode) {
-                    return closure.call();
-                }
-            } else {
+            synchronized (rootNode != null ? rootNode : GIL) {
                 return closure.call();
             }
-        } catch (RuntimeException e) {
+        } catch (RuntimeException | Error e) {
             throw e;
         } catch (Exception e) {
             throw new RuntimeException(e);
@@ -625,4 +616,6 @@
         }
         return "";
     }
+
+    private static final Object GIL = new Object();
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Mar 02 19:11:22 2015 +0100
@@ -696,6 +696,42 @@
         return false;
     }
 
+    /**
+     * Executes a closure for every non-null child of the parent node.
+     *
+     * @return {@code true} if all children were visited, {@code false} otherwise
+     */
+    public static boolean forEachChild(Node parent, NodeVisitor visitor) {
+        Objects.requireNonNull(visitor);
+        NodeClass parentNodeClass = NodeClass.get(parent.getClass());
+
+        for (NodeField field : parentNodeClass.getChildFields()) {
+            Object child = field.getObject(parent);
+            if (child != null) {
+                if (!visitor.visit((Node) child)) {
+                    return false;
+                }
+            }
+        }
+
+        for (NodeField field : parentNodeClass.getChildrenFields()) {
+            Object arrayObject = field.getObject(parent);
+            if (arrayObject != null) {
+                Object[] array = (Object[]) arrayObject;
+                for (int i = 0; i < array.length; i++) {
+                    Object child = array[i];
+                    if (child != null) {
+                        if (!visitor.visit((Node) child)) {
+                            return false;
+                        }
+                    }
+                }
+            }
+        }
+
+        return true;
+    }
+
     /** Returns all declared fields in the class hierarchy. */
     private static Field[] getAllFields(Class<? extends Object> clazz) {
         Field[] declaredFields = clazz.getDeclaredFields();
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeVisitor.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeVisitor.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/RootNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/UnexpectedResultException.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/serial/SerializerConstantPool.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/CoverageTracker.java	Mon Mar 02 19:11:22 2015 +0100
@@ -27,13 +27,11 @@
 import java.io.*;
 import java.util.*;
 import java.util.Map.Entry;
-import java.util.concurrent.atomic.*;
 
 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.*;
-import com.oracle.truffle.api.nodes.Node.Child;
 import com.oracle.truffle.api.source.*;
 
 /**
@@ -160,7 +158,7 @@
                 curSource = source;
                 curLineTable = new Long[source.getLineCount()];
             }
-            curLineTable[lineNo - 1] = entry.getValue().count.longValue();
+            curLineTable[lineNo - 1] = entry.getValue().count;
         }
         if (curSource != null) {
             result.put(curSource, curLineTable);
@@ -206,7 +204,7 @@
             while (curLineNo < lineNo) {
                 displayLine(out, null, curSource, curLineNo++);
             }
-            displayLine(out, entry.getValue().count, curSource, curLineNo++);
+            displayLine(out, entry.getValue(), curSource, curLineNo++);
         }
         if (curSource != null) {
             while (curLineNo <= curSource.getLineCount()) {
@@ -215,11 +213,11 @@
         }
     }
 
-    private static void displayLine(PrintStream out, AtomicLong value, Source source, int lineNo) {
-        if (value == null) {
+    private static void displayLine(PrintStream out, CoverageRecord record, Source source, int lineNo) {
+        if (record == null) {
             out.format("%14s", " ");
         } else {
-            out.format("(%12d)", value.longValue());
+            out.format("(%12d)", record.count);
         }
         out.format(" %3d: ", lineNo);
         out.println(source.getCode(lineNo));
@@ -227,33 +225,25 @@
 
     /**
      * 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.
-     * <p>
-     * In contrast, a primitive field would <em>not</em> be shared among clones and resulting counts
-     * would not be accurate.
+     * "execution calls" to the instrumented node.
      */
-    private final class CoverageEventListener extends DefaultEventListener {
+    private final class CoverageRecord extends DefaultEventListener {
 
-        /**
-         * Shared by all clones of the associated instrument and by the table of counters for the
-         * line.
-         */
-        private final AtomicLong count;
+        private final SourceSection srcSection; // The text of the code being counted
+        private Instrument instrument;  // The attached Instrument, in case need to remove.
+        private long count = 0;
 
-        CoverageEventListener(AtomicLong count) {
-            this.count = count;
+        CoverageRecord(SourceSection srcSection) {
+            this.srcSection = srcSection;
         }
 
         @Override
-        public void enter(Node node, VirtualFrame frame) {
+        public void enter(Node node, VirtualFrame vFrame) {
             if (isEnabled()) {
-                count.getAndIncrement();
+                count++;
             }
         }
+
     }
 
     private static final class LineLocationEntryComparator implements Comparator<Entry<LineLocation, CoverageRecord>> {
@@ -282,35 +272,23 @@
                     if (record != null) {
                         // Another node starts on same line; count only the first (textually)
                         if (srcSection.getCharIndex() > record.srcSection.getCharIndex()) {
-                            // Record already in place, corresponds to code earlier on line
+                            // Existing record, corresponds to code earlier on line
                             return;
                         } else {
-                            // Record already in place, corresponds to later code; replace it
+                            // Existing record, corresponds to code at a later position; replace it
                             record.instrument.dispose();
                         }
                     }
-                    final AtomicLong count = new AtomicLong();
-                    final CoverageEventListener eventListener = new CoverageEventListener(count);
-                    final Instrument instrument = Instrument.create(eventListener, CoverageTracker.class.getSimpleName());
+
+                    final CoverageRecord coverage = new CoverageRecord(srcSection);
+                    final Instrument instrument = Instrument.create(coverage, CoverageTracker.class.getSimpleName());
+                    coverage.instrument = instrument;
                     instruments.add(instrument);
                     probe.attach(instrument);
-                    coverageMap.put(lineLocation, new CoverageRecord(srcSection, instrument, count));
+                    coverageMap.put(lineLocation, coverage);
                 }
             }
         }
     }
 
-    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;
-
-        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/LineToProbesMap.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/LineToProbesMap.java	Mon Mar 02 19:11:22 2015 +0100
@@ -32,7 +32,7 @@
 import com.oracle.truffle.api.source.*;
 
 /**
- * An {@link InstrumentationTool} that builds a map of every {@Probe} attached to some AST,
+ * An {@link InstrumentationTool} that builds a map of every {@link Probe} attached to some AST,
  * indexed by {@link Source} and line number.
  */
 public final class LineToProbesMap extends InstrumentationTool {
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/tools/NodeExecCounter.java	Mon Mar 02 19:11:22 2015 +0100
@@ -97,7 +97,7 @@
      */
     private final TruffleEventListener eventListener = new DefaultEventListener() {
         @Override
-        public void enter(Node node, VirtualFrame frame) {
+        public void enter(Node node, VirtualFrame vFrame) {
             if (isEnabled()) {
                 final Class<?> nodeClass = node.getClass();
                 /*
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ConditionProfile.java	Mon Mar 02 19:11:22 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/PrimitiveValueProfile.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/PrimitiveValueProfile.java	Mon Mar 02 19:11:22 2015 +0100
@@ -51,25 +51,26 @@
     @SuppressWarnings("unchecked")
     @Override
     public Object profile(Object value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Byte && value instanceof Byte && (byte) cachedValue == (byte) value) {
-                return cachedValue;
-            } else if (cachedValue instanceof Short && value instanceof Short && (short) cachedValue == (short) value) {
-                return cachedValue;
-            } else if (cachedValue instanceof Integer && value instanceof Integer && (int) cachedValue == (int) value) {
-                return cachedValue;
-            } else if (cachedValue instanceof Long && value instanceof Long && (long) cachedValue == (long) value) {
-                return cachedValue;
-            } else if (cachedValue instanceof Float && value instanceof Float && exactCompare((float) cachedValue, (float) value)) {
-                return cachedValue;
-            } else if (cachedValue instanceof Double && value instanceof Double && exactCompare((double) cachedValue, (double) value)) {
-                return cachedValue;
-            } else if (cachedValue instanceof Boolean && value instanceof Boolean && (boolean) cachedValue == (boolean) value) {
-                return cachedValue;
-            } else if (cachedValue instanceof Character && value instanceof Character && (char) cachedValue == (char) value) {
-                return cachedValue;
-            } else if (cachedValue == value) {
-                return cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Byte && value instanceof Byte && (byte) snapshot == (byte) value) {
+                return snapshot;
+            } else if (snapshot instanceof Short && value instanceof Short && (short) snapshot == (short) value) {
+                return snapshot;
+            } else if (snapshot instanceof Integer && value instanceof Integer && (int) snapshot == (int) value) {
+                return snapshot;
+            } else if (snapshot instanceof Long && value instanceof Long && (long) snapshot == (long) value) {
+                return snapshot;
+            } else if (snapshot instanceof Float && value instanceof Float && exactCompare((float) snapshot, (float) value)) {
+                return snapshot;
+            } else if (snapshot instanceof Double && value instanceof Double && exactCompare((double) snapshot, (double) value)) {
+                return snapshot;
+            } else if (snapshot instanceof Boolean && value instanceof Boolean && (boolean) snapshot == (boolean) value) {
+                return snapshot;
+            } else if (snapshot instanceof Character && value instanceof Character && (char) snapshot == (char) value) {
+                return snapshot;
+            } else if (snapshot == value) {
+                return snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -78,9 +79,10 @@
     }
 
     public byte profile(byte value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Byte && (byte) cachedValue == value) {
-                return (byte) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Byte && (byte) snapshot == value) {
+                return (byte) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -89,9 +91,10 @@
     }
 
     public short profile(short value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Short && (short) cachedValue == value) {
-                return (short) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Short && (short) snapshot == value) {
+                return (short) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -100,9 +103,10 @@
     }
 
     public int profile(int value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Integer && (int) cachedValue == value) {
-                return (int) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Integer && (int) snapshot == value) {
+                return (int) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -111,9 +115,10 @@
     }
 
     public long profile(long value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Long && (long) cachedValue == value) {
-                return (long) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Long && (long) snapshot == value) {
+                return (long) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -122,9 +127,10 @@
     }
 
     public float profile(float value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Float && exactCompare((float) cachedValue, value)) {
-                return (float) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Float && exactCompare((float) snapshot, value)) {
+                return (float) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -133,9 +139,10 @@
     }
 
     public double profile(double value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Double && exactCompare((double) cachedValue, value)) {
-                return (double) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Double && exactCompare((double) snapshot, value)) {
+                return (double) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -144,9 +151,10 @@
     }
 
     public boolean profile(boolean value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Boolean && (boolean) cachedValue == value) {
-                return (boolean) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Boolean && (boolean) snapshot == value) {
+                return (boolean) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -155,9 +163,10 @@
     }
 
     public char profile(char value) {
-        if (cachedValue != GENERIC) {
-            if (cachedValue instanceof Character && (char) cachedValue == value) {
-                return (char) cachedValue;
+        Object snapshot = this.cachedValue;
+        if (snapshot != GENERIC) {
+            if (snapshot instanceof Character && (char) snapshot == value) {
+                return (char) snapshot;
             } else {
                 cacheMiss(value);
             }
@@ -183,6 +192,7 @@
     }
 
     private void cacheMiss(Object value) {
+        // TODO should we try to handle this more atomically?
         CompilerDirectives.transferToInterpreterAndInvalidate();
         if (cachedValue == UNINITIALIZED) {
             cachedValue = value;
@@ -208,17 +218,18 @@
     }
 
     private String formatValue() {
-        if (cachedValue == null) {
+        Object snapshot = this.cachedValue;
+        if (snapshot == null) {
             return "null";
-        } else if (cachedValue == UNINITIALIZED) {
+        } else if (snapshot == UNINITIALIZED) {
             return "uninitialized";
-        } else if (cachedValue == GENERIC) {
+        } else if (snapshot == GENERIC) {
             return "generic";
-        } else if (cachedValue instanceof Byte || cachedValue instanceof Short || cachedValue instanceof Integer || cachedValue instanceof Long || cachedValue instanceof Float ||
-                        cachedValue instanceof Double || cachedValue instanceof Boolean || cachedValue instanceof Character) {
-            return String.format("%s=%s", cachedValue.getClass().getSimpleName(), cachedValue);
+        } else if (snapshot instanceof Byte || snapshot instanceof Short || snapshot instanceof Integer || snapshot instanceof Long || snapshot instanceof Float || snapshot instanceof Double ||
+                        snapshot instanceof Boolean || snapshot instanceof Character) {
+            return String.format("%s=%s", snapshot.getClass().getSimpleName(), snapshot);
         } else {
-            return String.format("%s@%x", cachedValue.getClass().getSimpleName(), Objects.hash(cachedValue));
+            return String.format("%s@%x", snapshot.getClass().getSimpleName(), Objects.hash(snapshot));
         }
     }
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Mon Mar 02 19:11:22 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.object/src/com/oracle/truffle/object/ShapeImpl.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.object/src/com/oracle/truffle/object/ShapeImpl.java	Mon Mar 02 19:11:22 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;
     }
 
@@ -355,9 +353,8 @@
      */
     private ShapeImpl addPropertyInternal(Property prop) {
         CompilerAsserts.neverPartOfCompilation();
-        assert prop.isShadow() || !(this.hasProperty(prop.getKey())) : "duplicate property";
+        assert prop.isShadow() || !(this.hasProperty(prop.getKey())) : "duplicate property " + prop.getKey();
         assert !getPropertyListInternal(false).contains(prop);
-        // invalidatePropertyAssumption(prop.getName());
 
         AddPropertyTransition addTransition = new AddPropertyTransition(prop);
         ShapeImpl cachedShape = queryTransition(addTransition);
@@ -655,7 +652,7 @@
                 newShape = newShape.applyTransition(previous, true);
             }
 
-            getTransitionMapForWrite().put(transition, newShape);
+            addIndirectTransition(transition, newShape);
             return newShape;
         } else {
             return null;
@@ -901,7 +898,7 @@
     private Property[] createPropertiesArray() {
         propertyListAllocCount.inc();
         Property[] propertiesArray = new Property[getPropertyCount()];
-        List<Property> ownProperties = getPropertyList(ALL);
+        List<Property> ownProperties = getPropertyList();
         assert ownProperties.size() == getPropertyCount();
         for (int i = 0; i < getPropertyCount(); i++) {
             propertiesArray[i] = ownProperties.get(i);
@@ -1101,7 +1098,7 @@
     /**
      * Match all filter.
      */
-    public static final Pred<Property> ALL = new Pred<Property>() {
+    private static final Pred<Property> ALL = new Pred<Property>() {
         public boolean test(Property t) {
             return true;
         }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLExpressionWrapperNode.java	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/instrument/SLStatementWrapperNode.java	Mon Mar 02 19:11:22 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/hotspot/.cproject	Mon Mar 02 18:44:14 2015 +0100
+++ b/hotspot/.cproject	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/hotspot/.settings/org.eclipse.cdt.core.prefs	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/mx/eclipse-settings/org.eclipse.jdt.core.prefs	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/mx/mx_graal.py	Mon Mar 02 19:11:22 2015 +0100
@@ -1717,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	Mon Mar 02 18:44:14 2015 +0100
+++ b/mx/suite.py	Mon Mar 02 19:11:22 2015 +0100
@@ -591,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",
@@ -801,7 +802,6 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
-        "com.oracle.graal.api.directives",
         "com.oracle.graal.phases",
       ],
       "checkstyle" : "com.oracle.graal.graph",
@@ -851,6 +851,7 @@
       "subDir" : "graal",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "com.oracle.graal.api.directives",
         "com.oracle.graal.test",
         "com.oracle.graal.printer",
         "com.oracle.graal.runtime",
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/layer.xml	Mon Mar 02 19:11:22 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	Mon Mar 02 19:11:22 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	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/classfile/classFileParser.cpp	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/classfile/systemDictionary.hpp	Mon Mar 02 19:11:22 2015 +0100
@@ -198,7 +198,6 @@
   GRAAL_ONLY(do_klass(HotSpotNmethod_klass,                  com_oracle_graal_hotspot_meta_HotSpotNmethod,                 Graal)) \
   GRAAL_ONLY(do_klass(HotSpotResolvedJavaMethodImpl_klass,   com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethodImpl,  Graal)) \
   GRAAL_ONLY(do_klass(HotSpotResolvedObjectTypeImpl_klass,   com_oracle_graal_hotspot_meta_HotSpotResolvedObjectTypeImpl,  Graal)) \
-  GRAAL_ONLY(do_klass(HotSpotMonitorValue_klass,             com_oracle_graal_hotspot_meta_HotSpotMonitorValue,            Graal)) \
   GRAAL_ONLY(do_klass(HotSpotCompressedNullConstant_klass,   com_oracle_graal_hotspot_meta_HotSpotCompressedNullConstant,  Graal)) \
   GRAAL_ONLY(do_klass(HotSpotObjectConstantImpl_klass,       com_oracle_graal_hotspot_meta_HotSpotObjectConstantImpl,      Graal)) \
   GRAAL_ONLY(do_klass(HotSpotMetaspaceConstantImpl_klass,    com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstantImpl,   Graal)) \
@@ -227,6 +226,7 @@
   GRAAL_ONLY(do_klass(RegisterValue_klass,                   com_oracle_graal_api_code_RegisterValue,                      Graal)) \
   GRAAL_ONLY(do_klass(RegisterCategory_klass,                com_oracle_graal_api_code_Register_RegisterCategory,          Graal)) \
   GRAAL_ONLY(do_klass(StackSlot_klass,                       com_oracle_graal_api_code_StackSlot,                          Graal)) \
+  GRAAL_ONLY(do_klass(StackLockValue_klass,                  com_oracle_graal_api_code_StackLockValue,                     Graal)) \
   GRAAL_ONLY(do_klass(VirtualObject_klass,                   com_oracle_graal_api_code_VirtualObject,                      Graal)) \
   GRAAL_ONLY(do_klass(SpeculationLog_klass,                  com_oracle_graal_api_code_SpeculationLog,                     Graal)) \
   GRAAL_ONLY(do_klass(JavaConstant_klass,                    com_oracle_graal_api_meta_JavaConstant,                       Graal)) \
--- a/src/share/vm/classfile/vmSymbols.hpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon Mar 02 19:11:22 2015 +0100
@@ -305,7 +305,6 @@
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotNmethod,             "com/oracle/graal/hotspot/meta/HotSpotNmethod"))                  \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotResolvedJavaMethodImpl, "com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl")) \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotResolvedObjectTypeImpl, "com/oracle/graal/hotspot/meta/HotSpotResolvedObjectTypeImpl")) \
-  GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotMonitorValue,        "com/oracle/graal/hotspot/meta/HotSpotMonitorValue"))             \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotCompressedNullConstant, "com/oracle/graal/hotspot/meta/HotSpotCompressedNullConstant")) \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotObjectConstantImpl,  "com/oracle/graal/hotspot/meta/HotSpotObjectConstantImpl"))       \
   GRAAL_ONLY(template(com_oracle_graal_hotspot_meta_HotSpotMetaspaceConstantImpl,"com/oracle/graal/hotspot/meta/HotSpotMetaspaceConstantImpl"))   \
@@ -343,6 +342,7 @@
   GRAAL_ONLY(template(com_oracle_graal_api_code_RegisterValue,                  "com/oracle/graal/api/code/RegisterValue"))                       \
   GRAAL_ONLY(template(com_oracle_graal_api_code_Register_RegisterCategory,      "com/oracle/graal/api/code/Register$RegisterCategory"))           \
   GRAAL_ONLY(template(com_oracle_graal_api_code_StackSlot,                      "com/oracle/graal/api/code/StackSlot"))                           \
+  GRAAL_ONLY(template(com_oracle_graal_api_code_StackLockValue,                 "com/oracle/graal/api/code/StackLockValue"))                      \
   GRAAL_ONLY(template(com_oracle_graal_api_code_VirtualObject,                  "com/oracle/graal/api/code/VirtualObject"))                       \
   GRAAL_ONLY(template(com_oracle_graal_api_code_RegisterSaveLayout,             "com/oracle/graal/api/code/RegisterSaveLayout"))                  \
   GRAAL_ONLY(template(com_oracle_graal_api_code_InvalidInstalledCodeException,  "com/oracle/graal/api/code/InvalidInstalledCodeException"))       \
--- a/src/share/vm/code/codeBlob.hpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/codeBlob.hpp	Mon Mar 02 19:11:22 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/debugInfo.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/debugInfo.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -52,7 +52,7 @@
 #ifdef ASSERT
   assert(_obj_pool != NULL, "object pool does not exist");
   for (int i = _obj_pool->length() - 1; i >= 0; i--) {
-    assert(((ObjectValue*) _obj_pool->at(i))->id() != id, "should not be read twice");
+    assert(_obj_pool->at(i)->as_ObjectValue()->id() != id, "should not be read twice");
   }
 #endif
   ObjectValue* result = new ObjectValue(id);
@@ -66,7 +66,7 @@
   int id = read_int();
   assert(_obj_pool != NULL, "object pool does not exist");
   for (int i = _obj_pool->length() - 1; i >= 0; i--) {
-    ObjectValue* ov = (ObjectValue*) _obj_pool->at(i);
+    ObjectValue* ov = _obj_pool->at(i)->as_ObjectValue();
     if (ov->id() == id) {
       return ov;
     }
--- a/src/share/vm/code/debugInfo.hpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/debugInfo.hpp	Mon Mar 02 19:11:22 2015 +0100
@@ -41,6 +41,7 @@
 // - ConstantValue   describes a constant
 
 class ConstantOopReadValue;
+class ObjectValue;
 
 class ScopeValue: public ResourceObj {
  public:
@@ -58,6 +59,11 @@
     return (ConstantOopReadValue*) this;
   }
 
+  ObjectValue* as_ObjectValue() {
+    assert(is_object(), "must be");
+    return (ObjectValue*)this;
+  }
+
   // Serialization of debugging information
   virtual void write_on(DebugInfoWriteStream* stream) = 0;
   static ScopeValue* read_from(DebugInfoReadStream* stream);
--- a/src/share/vm/code/debugInfoRec.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/debugInfoRec.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -392,7 +392,7 @@
   PcDesc* last_pd = &_pcs[_pcs_length-1];
   if (objects != NULL) {
     for (int i = objects->length() - 1; i >= 0; i--) {
-      ((ObjectValue*) objects->at(i))->set_visited(false);
+      objects->at(i)->as_ObjectValue()->set_visited(false);
     }
   }
   int offset = serialize_scope_values(objects);
--- a/src/share/vm/code/dependencies.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/dependencies.cpp	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/dependencies.hpp	Mon Mar 02 19:11:22 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/code/nmethod.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/nmethod.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -2749,7 +2749,10 @@
       continue;
 
     ScopeDesc* sd = scope_desc_at(p->real_pc(this));
-    sd->print_on(tty, p);
+    while (sd != NULL) {
+      sd->print_on(tty, p);
+      sd = sd->sender();
+    }
   }
 }
 
--- a/src/share/vm/code/scopeDesc.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/code/scopeDesc.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -230,7 +230,7 @@
   if (NOT_GRAAL(DoEscapeAnalysis &&) is_top() && _objects != NULL) {
     tty->print_cr("Objects");
     for (int i = 0; i < _objects->length(); i++) {
-      ObjectValue* sv = (ObjectValue*) _objects->at(i);
+      ObjectValue* sv = _objects->at(i)->as_ObjectValue();
       tty->print(" - %d: ", sv->id());
       sv->print_fields_on(tty);
       tty->cr();
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -365,19 +365,19 @@
 }
 
 MonitorValue* CodeInstaller::get_monitor_value(oop value, int total_frame_size, GrowableArray<ScopeValue*>* objects, OopRecorder* oop_recorder) {
-  guarantee(value->is_a(HotSpotMonitorValue::klass()), "Monitors must be of type MonitorValue");
+  guarantee(value->is_a(StackLockValue::klass()), "Monitors must be of type MonitorValue");
 
   ScopeValue* second = NULL;
-  ScopeValue* owner_value = get_scope_value(HotSpotMonitorValue::owner(value), total_frame_size, objects, second, oop_recorder);
+  ScopeValue* owner_value = get_scope_value(StackLockValue::owner(value), total_frame_size, objects, second, oop_recorder);
   assert(second == NULL, "monitor cannot occupy two stack slots");
 
-  ScopeValue* lock_data_value = get_scope_value(HotSpotMonitorValue::slot(value), total_frame_size, objects, second, oop_recorder);
+  ScopeValue* lock_data_value = get_scope_value(StackLockValue::slot(value), total_frame_size, objects, second, oop_recorder);
   assert(second == lock_data_value, "monitor is LONG value that occupies two stack slots");
   assert(lock_data_value->is_location(), "invalid monitor location");
   Location lock_data_loc = ((LocationValue*)lock_data_value)->location();
 
   bool eliminated = false;
-  if (HotSpotMonitorValue::eliminated(value)) {
+  if (StackLockValue::eliminated(value)) {
     eliminated = true;
   }
 
@@ -468,7 +468,7 @@
       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, env, id, false, installed_code, speculation_log);
+        GraalCompiler::instance(), _debug_recorder, _dependencies, env, id, false, installed_code, compiled_code, speculation_log);
     cb = nm;
   }
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/graal/graalEnv.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -421,11 +421,11 @@
 // ------------------------------------------------------------------
 // Check for changes to the system dictionary during compilation
 // class loads, evolution, breakpoints
-bool GraalEnv::check_for_system_dictionary_modification(Dependencies* dependencies, GraalEnv* env) {
+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()) {
-      // Hotswapping or breakpointing was enabled during compilation
+      *failure_detail = (char*) "Hotswapping or breakpointing was enabled during compilation";
       return false;
     }
   }
@@ -440,8 +440,14 @@
   }
 
   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) {
@@ -470,11 +476,14 @@
                                 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);
@@ -487,7 +496,7 @@
     dependencies->encode_content_bytes();
 
     // Check for {class loads, evolution, breakpoints} during compilation
-    if (!check_for_system_dictionary_modification(dependencies, env)) {
+    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) {
@@ -504,83 +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.)
-      CompileTask* task = env == NULL ? NULL : env->task();
-      if (task != NULL)  task->set_code(nm);
-
-      if (installed_code->is_a(HotSpotNmethod::klass()) && HotSpotNmethod::isDefault(installed_code())) {
-        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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/graal/graalEnv.hpp	Mon Mar 02 19:11:22 2015 +0100
@@ -133,7 +133,7 @@
 
   // Helper routine for determining the validity of a compilation
   // with respect to concurrent class loading.
-  static bool check_for_system_dictionary_modification(Dependencies* target, GraalEnv* env);
+  static bool check_for_system_dictionary_modification(Dependencies* target, Handle compiled_code, GraalEnv* env, char** failure_detail);
 
 public:
   CompileTask* task() { return _task; }
@@ -156,6 +156,7 @@
                        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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Mon Mar 02 19:11:22 2015 +0100
@@ -82,6 +82,7 @@
   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, graalEnv)                                                                                                               \
@@ -242,10 +243,10 @@
     oop_field(VirtualObject, type, "Lcom/oracle/graal/api/meta/ResolvedJavaType;")                                                                             \
     objArrayOop_field(VirtualObject, values, "[Lcom/oracle/graal/api/meta/JavaValue;")                                                                         \
   end_class                                                                                                                                                    \
-  start_class(HotSpotMonitorValue)                                                                                                                             \
-    oop_field(HotSpotMonitorValue, owner, "Lcom/oracle/graal/api/meta/JavaValue;")                                                                             \
-    oop_field(HotSpotMonitorValue, slot, "Lcom/oracle/graal/api/code/StackSlotValue;")                                                                              \
-    boolean_field(HotSpotMonitorValue, eliminated)                                                                                                             \
+  start_class(StackLockValue)                                                                                                                                 \
+    oop_field(StackLockValue, owner, "Lcom/oracle/graal/api/meta/JavaValue;")                                                                                  \
+    oop_field(StackLockValue, slot, "Lcom/oracle/graal/api/code/StackSlotValue;")                                                                              \
+    boolean_field(StackLockValue, eliminated)                                                                                                                  \
   end_class                                                                                                                                                    \
   start_class(SpeculationLog)                                                                                                                                  \
     oop_field(SpeculationLog, lastFailed, "Ljava/lang/Object;")                                                                                                \
--- a/src/share/vm/graal/vmStructs_graal.hpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/graal/vmStructs_graal.hpp	Mon Mar 02 19:11:22 2015 +0100
@@ -31,7 +31,6 @@
 #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)      \
@@ -40,6 +39,7 @@
   nonstatic_field(GraalEnv,      _jvmti_can_hotswap_or_post_breakpoint, bool) \
 
 #define VM_TYPES_GRAAL(declare_type, declare_toplevel_type)                   \
+  declare_toplevel_type(GraalEnv)                                             \
 
 #define VM_INT_CONSTANTS_GRAAL(declare_constant, declare_preprocessor_constant)                   \
   declare_constant(Deoptimization::Reason_unreached0)                                             \
--- a/src/share/vm/oops/instanceKlass.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/oops/instanceKlass.cpp	Mon Mar 02 19:11:22 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	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/oops/instanceKlass.hpp	Mon Mar 02 19:11:22 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/src/share/vm/runtime/vframe.cpp	Mon Mar 02 18:44:14 2015 +0100
+++ b/src/share/vm/runtime/vframe.cpp	Mon Mar 02 19:11:22 2015 +0100
@@ -274,7 +274,7 @@
   // Get oopmap describing oops and int for current bci
   InterpreterOopMap oop_mask;
   if ((TraceDeoptimization && Verbose) GRAAL_ONLY( || PrintDeoptimizationDetails)) {
-    methodHandle m_h(thread(), method());
+    methodHandle m_h(Thread::current(), method());
     OopMapCache::compute_one_oop_map(m_h, bci(), &oop_mask);
   } else {
     method()->mask_for(bci(), &oop_mask);