changeset 20004:220c494e5088

Merge
author Stefan Anzinger <stefan.anzinger@oracle.com>
date Mon, 23 Mar 2015 16:11:48 +0100
parents 422e60a2f4b9 (current diff) 5aa0cb2914f8 (diff)
children 1671d9111c47 3819bcdde898
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter
diffstat 147 files changed, 3206 insertions(+), 3377 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGELOG.md	Mon Mar 23 15:58:36 2015 +0100
+++ b/CHANGELOG.md	Mon Mar 23 16:11:48 2015 +0100
@@ -17,6 +17,8 @@
 * Instrumentation:  AST "probing" is now safe and implemented by Node.probe(); language implementors need only implement Node.isInstrumentable() and Node.createWrapperNode().
 * Instrumentation:  A new framework defines a category of  simple "instrumentation tools" that can be created, configured, and installed, after which they autonomously collect execution data of some kind.
 * Instrumentation:  A new example "instrumentation tool" is a language-agnostic collector of code coverage information (CoverageTracker); there are two other examples.
+* Removed unsafe compiler directives; use `sun.misc.Unsafe` instead.
+* Removed `Node#onAdopt()`.
 
 ### Truffle-DSL
 * Implemented a new generated code layout that reduces the code size.
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Mon Mar 23 16:11:48 2015 +0100
@@ -88,7 +88,7 @@
 
     @Override
     public String toString() {
-        return name + (isImmutable() ? ":immutable" : ":mutable");
+        return name + (isImmutable() ? ":final" : "");
     }
 
     /**
--- a/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.asm.amd64/src/com/oracle/graal/asm/amd64/AMD64Assembler.java	Mon Mar 23 16:11:48 2015 +0100
@@ -601,11 +601,14 @@
         public static final AMD64RMOp MOVSXB = new AMD64RMOp("MOVSXB",       P_0F, 0xBE, false, true, OpAssertion.IntegerAssertion);
         public static final AMD64RMOp MOVSX  = new AMD64RMOp("MOVSX",        P_0F, 0xBF, OpAssertion.No16BitAssertion);
         public static final AMD64RMOp MOVSXD = new AMD64RMOp("MOVSXD",             0x63, OpAssertion.QwordOnlyAssertion);
+        public static final AMD64RMOp MOVB   = new AMD64RMOp("MOVB",               0x8A, OpAssertion.ByteAssertion);
         public static final AMD64RMOp MOV    = new AMD64RMOp("MOV",                0x8B);
 
-        // MOVD and MOVQ are the same opcode, just with different operand size prefix
+        // MOVD/MOVQ and MOVSS/MOVSD are the same opcode, just with different operand size prefix
         public static final AMD64RMOp MOVD   = new AMD64RMOp("MOVD",   0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
         public static final AMD64RMOp MOVQ   = new AMD64RMOp("MOVQ",   0x66, P_0F, 0x6E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+        public static final AMD64RMOp MOVSS  = new AMD64RMOp("MOVSS",        P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE);
+        public static final AMD64RMOp MOVSD  = new AMD64RMOp("MOVSD",        P_0F, 0x10, OpAssertion.FloatingAssertion, CPUFeature.SSE);
 
         // TEST is documented as MR operation, but it's symmetric, and using it as RM operation is more convenient.
         public static final AMD64RMOp TESTB  = new AMD64RMOp("TEST",               0x84, OpAssertion.ByteAssertion);
@@ -628,6 +631,10 @@
             this(opcode, 0, prefix, op, assertion, null);
         }
 
+        protected AMD64RMOp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, 0, prefix, op, assertion, feature);
+        }
+
         protected AMD64RMOp(String opcode, int prefix, int op, boolean dstIsByte, boolean srcIsByte, OpAssertion assertion) {
             super(opcode, 0, prefix, op, dstIsByte, srcIsByte, assertion, null);
         }
@@ -659,12 +666,17 @@
      */
     public static class AMD64MROp extends AMD64RROp {
         // @formatter:off
+        public static final AMD64MROp MOVB   = new AMD64MROp("MOVB",               0x88, OpAssertion.ByteAssertion);
         public static final AMD64MROp MOV    = new AMD64MROp("MOV",                0x89);
 
         // MOVD and MOVQ are the same opcode, just with different operand size prefix
         // Note that as MR opcodes, they have reverse operand order, so the IntToFloatingAssertion must be used.
         public static final AMD64MROp MOVD   = new AMD64MROp("MOVD",   0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
         public static final AMD64MROp MOVQ   = new AMD64MROp("MOVQ",   0x66, P_0F, 0x7E, OpAssertion.IntToFloatingAssertion, CPUFeature.SSE2);
+
+        // MOVSS and MOVSD are the same opcode, just with different operand size prefix
+        public static final AMD64MROp MOVSS  = new AMD64MROp("MOVSS",        P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE);
+        public static final AMD64MROp MOVSD  = new AMD64MROp("MOVSD",        P_0F, 0x11, OpAssertion.FloatingAssertion, CPUFeature.SSE);
         // @formatter:on
 
         protected AMD64MROp(String opcode, int op) {
@@ -680,7 +692,11 @@
         }
 
         protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion) {
-            this(opcode, 0, prefix, op, assertion, null);
+            this(opcode, prefix, op, assertion, null);
+        }
+
+        protected AMD64MROp(String opcode, int prefix, int op, OpAssertion assertion, CPUFeature feature) {
+            this(opcode, 0, prefix, op, assertion, feature);
         }
 
         protected AMD64MROp(String opcode, int prefix1, int prefix2, int op, OpAssertion assertion, CPUFeature feature) {
@@ -747,6 +763,7 @@
      */
     public static class AMD64MIOp extends AMD64ImmOp {
         // @formatter:off
+        public static final AMD64MIOp MOVB = new AMD64MIOp("MOVB", true,  0xC6, 0, OpAssertion.ByteAssertion);
         public static final AMD64MIOp MOV  = new AMD64MIOp("MOV",  false, 0xC7, 0);
         public static final AMD64MIOp TEST = new AMD64MIOp("TEST", false, 0xF7, 0);
         // @formatter:on
@@ -754,7 +771,11 @@
         private final int ext;
 
         protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext) {
-            this(opcode, immIsByte, 0, op, ext, OpAssertion.IntegerAssertion);
+            this(opcode, immIsByte, op, ext, OpAssertion.IntegerAssertion);
+        }
+
+        protected AMD64MIOp(String opcode, boolean immIsByte, int op, int ext, OpAssertion assertion) {
+            this(opcode, immIsByte, 0, op, ext, assertion);
         }
 
         protected AMD64MIOp(String opcode, boolean immIsByte, int prefix, int op, int ext, OpAssertion assertion) {
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64LIRGenerator.java	Mon Mar 23 16:11:48 2015 +0100
@@ -50,7 +50,6 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.compiler.common.spi.*;
-import com.oracle.graal.compiler.common.util.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.JumpOp;
 import com.oracle.graal.lir.amd64.*;
@@ -68,7 +67,6 @@
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveToRegOp;
 import com.oracle.graal.lir.amd64.AMD64Move.StackLeaOp;
-import com.oracle.graal.lir.amd64.AMD64Move.ZeroExtendLoadOp;
 import com.oracle.graal.lir.gen.*;
 import com.oracle.graal.phases.util.*;
 
@@ -107,28 +105,6 @@
         }
     }
 
-    /**
-     * Checks whether the supplied constant can be used without loading it into a register for store
-     * operations, i.e., on the right hand side of a memory access.
-     *
-     * @param c The constant to check.
-     * @return True if the constant can be used directly, false if the constant needs to be in a
-     *         register.
-     */
-    protected boolean canStoreConstant(JavaConstant c) {
-        // there is no immediate move of 64-bit constants on Intel
-        switch (c.getKind()) {
-            case Long:
-                return Util.isInt(c.asLong()) && !getCodeCache().needsDataPatch(c);
-            case Double:
-                return false;
-            case Object:
-                return c.isNull();
-            default:
-                return true;
-        }
-    }
-
     protected AMD64LIRInstruction createMove(AllocatableValue dst, Value src) {
         if (src instanceof AMD64AddressValue) {
             return new LeaOp(dst, (AMD64AddressValue) src);
@@ -290,14 +266,14 @@
     private void emitIntegerTest(Value a, Value b) {
         assert a.getKind().isNumericInteger();
         OperandSize size = a.getKind() == Kind.Long ? QWORD : DWORD;
-        if (isConstant(b)) {
-            append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(a), asConstant(b)));
-        } else if (isConstant(a)) {
-            append(new AMD64CompareConstOp(AMD64MIOp.TEST, size, asAllocatable(b), asConstant(a)));
+        if (isConstant(b) && NumUtil.is32bit(asConstant(b).asLong())) {
+            append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(a), (int) asConstant(b).asLong()));
+        } else if (isConstant(a) && NumUtil.is32bit(asConstant(a).asLong())) {
+            append(new AMD64BinaryConsumer.ConstOp(AMD64MIOp.TEST, size, asAllocatable(b), (int) asConstant(a).asLong()));
         } else if (isAllocatableValue(b)) {
-            append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a)));
+            append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(b), asAllocatable(a)));
         } else {
-            append(new AMD64CompareOp(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b)));
+            append(new AMD64BinaryConsumer.Op(AMD64RMOp.TEST, size, asAllocatable(a), asAllocatable(b)));
         }
     }
 
@@ -320,10 +296,10 @@
                 size = QWORD;
                 break;
             case Float:
-                append(new AMD64CompareOp(SSEOp.UCOMIS, PS, left, asAllocatable(right)));
+                append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PS, left, asAllocatable(right)));
                 return;
             case Double:
-                append(new AMD64CompareOp(SSEOp.UCOMIS, PD, left, asAllocatable(right)));
+                append(new AMD64BinaryConsumer.Op(SSEOp.UCOMIS, PD, left, asAllocatable(right)));
                 return;
             default:
                 throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind);
@@ -333,17 +309,16 @@
             JavaConstant c = asConstant(right);
             if (c.isDefaultForKind()) {
                 AMD64RMOp op = size == BYTE ? TESTB : TEST;
-                append(new AMD64CompareOp(op, size, left, left));
+                append(new AMD64BinaryConsumer.Op(op, size, left, left));
                 return;
             } else if (NumUtil.is32bit(c.asLong())) {
-                AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(c.asLong()));
-                append(new AMD64CompareConstOp(op, size, left, c));
+                append(new AMD64BinaryConsumer.ConstOp(CMP, size, left, (int) c.asLong()));
                 return;
             }
         }
 
         AMD64RMOp op = CMP.getRMOpcode(size);
-        append(new AMD64CompareOp(op, size, left, asAllocatable(right)));
+        append(new AMD64BinaryConsumer.Op(op, size, left, asAllocatable(right)));
     }
 
     /**
@@ -372,10 +347,10 @@
                 size = QWORD;
                 break;
             case Float:
-                append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state));
+                append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PS, asAllocatable(a), b, state));
                 return false;
             case Double:
-                append(new AMD64CompareMemoryOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state));
+                append(new AMD64BinaryConsumer.MemoryRMOp(SSEOp.UCOMIS, PD, asAllocatable(a), b, state));
                 return false;
             default:
                 throw GraalInternalError.shouldNotReachHere("unexpected kind: " + cmpKind);
@@ -390,8 +365,7 @@
 
     protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) {
         if (NumUtil.is32bit(a.asLong())) {
-            AMD64MIOp op = CMP.getMIOpcode(size, NumUtil.isByte(a.asLong()));
-            append(new AMD64CompareMemoryConstOp(op, size, b, a, state));
+            append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, (int) a.asLong(), state));
             return true;
         } else {
             return emitCompareRegMemoryOp(size, a, b, state);
@@ -400,7 +374,7 @@
 
     private boolean emitCompareRegMemoryOp(OperandSize size, Value a, AMD64AddressValue b, LIRFrameState state) {
         AMD64RMOp op = CMP.getRMOpcode(size);
-        append(new AMD64CompareMemoryOp(op, size, asAllocatable(a), b, state));
+        append(new AMD64BinaryConsumer.MemoryRMOp(op, size, asAllocatable(a), b, state));
         return false;
     }
 
@@ -435,16 +409,16 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Int:
-                append(new AMD64UnaryMOp(NEG, DWORD, result, input));
+                append(new AMD64Unary.MOp(NEG, DWORD, result, input));
                 break;
             case Long:
-                append(new AMD64UnaryMOp(NEG, QWORD, result, input));
+                append(new AMD64Unary.MOp(NEG, QWORD, result, input));
                 break;
             case Float:
-                append(new AMD64BinaryPatchOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16));
+                append(new AMD64Binary.DataOp(SSEOp.XOR, PS, result, input, JavaConstant.forFloat(Float.intBitsToFloat(0x80000000)), 16));
                 break;
             case Double:
-                append(new AMD64BinaryPatchOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16));
+                append(new AMD64Binary.DataOp(SSEOp.XOR, PD, result, input, JavaConstant.forDouble(Double.longBitsToDouble(0x8000000000000000L)), 16));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -458,10 +432,10 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Int:
-                append(new AMD64UnaryMOp(NOT, DWORD, result, input));
+                append(new AMD64Unary.MOp(NOT, DWORD, result, input));
                 break;
             case Long:
-                append(new AMD64UnaryMOp(NOT, QWORD, result, input));
+                append(new AMD64Unary.MOp(NOT, QWORD, result, input));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -492,7 +466,7 @@
     private Variable emitBinaryConst(AMD64BinaryArithmetic op, OperandSize size, boolean commutative, AllocatableValue a, JavaConstant b) {
         if (NumUtil.isInt(b.asLong())) {
             Variable result = newVariable(LIRKind.derive(a, b));
-            append(new AMD64BinaryConstOp(op, size, result, a, b));
+            append(new AMD64Binary.ConstOp(op, size, result, a, (int) b.asLong()));
             return result;
         } else {
             return emitBinaryVar(op.getRMOpcode(size), size, commutative, a, asAllocatable(b));
@@ -501,16 +475,16 @@
 
     private Variable emitBinaryConst(AMD64RMOp op, OperandSize size, AllocatableValue a, JavaConstant b) {
         Variable result = newVariable(LIRKind.derive(a, b));
-        append(new AMD64BinaryPatchOp(op, size, result, a, b));
+        append(new AMD64Binary.DataOp(op, size, result, a, b));
         return result;
     }
 
     private Variable emitBinaryVar(AMD64RMOp op, OperandSize size, boolean commutative, AllocatableValue a, AllocatableValue b) {
         Variable result = newVariable(LIRKind.derive(a, b));
         if (commutative) {
-            append(new AMD64BinaryCommutativeOp(op, size, result, a, b));
+            append(new AMD64Binary.CommutativeOp(op, size, result, a, b));
         } else {
-            append(new AMD64BinaryOp(op, size, result, a, b));
+            append(new AMD64Binary.Op(op, size, result, a, b));
         }
         return result;
     }
@@ -558,7 +532,7 @@
             }
 
             Variable ret = newVariable(LIRKind.derive(a, b));
-            append(new AMD64MulConstOp(op, size, ret, a, b));
+            append(new AMD64Binary.RMIOp(op, size, ret, a, imm));
             return ret;
         } else {
             return emitBinaryVar(AMD64RMOp.IMUL, size, true, a, asAllocatable(b));
@@ -628,13 +602,13 @@
 
     public Value emitBinaryMemory(AMD64RMOp op, OperandSize size, AllocatableValue a, AMD64AddressValue location, LIRFrameState state) {
         Variable result = newVariable(LIRKind.derive(a));
-        append(new AMD64BinaryMemoryOp(op, size, result, a, location, state));
+        append(new AMD64Binary.MemoryOp(op, size, result, a, location, state));
         return result;
     }
 
     protected Value emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, AMD64AddressValue address, LIRFrameState state) {
         Variable result = newVariable(LIRKind.value(kind));
-        append(new AMD64UnaryMemoryOp(op, size, result, address, state));
+        append(new AMD64Unary.MemoryOp(op, size, result, address, state));
         return result;
     }
 
@@ -642,7 +616,24 @@
         // Issue a zero extending load of the proper bit size and set the result to
         // the proper kind.
         Variable result = newVariable(LIRKind.value(resultBits == 32 ? Kind.Int : Kind.Long));
-        append(new ZeroExtendLoadOp(memoryKind, result, address, state));
+        switch (memoryKind) {
+            case Boolean:
+            case Byte:
+                append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, address, state));
+                break;
+            case Char:
+            case Short:
+                append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, address, state));
+                break;
+            case Int:
+                append(new AMD64Unary.MemoryOp(MOV, DWORD, result, address, state));
+                break;
+            case Long:
+                append(new AMD64Unary.MemoryOp(MOV, QWORD, result, address, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
         return result;
     }
 
@@ -805,9 +796,13 @@
         if (isConstant(b)) {
             JavaConstant c = asConstant(b);
             if (c.asLong() == 1) {
-                append(new AMD64UnaryMOp(op.m1Op, size, result, input));
+                append(new AMD64Unary.MOp(op.m1Op, size, result, input));
             } else {
-                append(new AMD64BinaryConstOp(op.miOp, size, result, input, c));
+                /*
+                 * c is implicitly masked to 5 or 6 bits by the CPU, so casting it to (int) is
+                 * always correct, even without the NumUtil.is32bit() test.
+                 */
+                append(new AMD64Binary.ConstOp(op.miOp, size, result, input, (int) c.asLong()));
             }
         } else {
             emitMove(RCX_I, b);
@@ -876,13 +871,13 @@
 
     private AllocatableValue emitConvertOp(LIRKind kind, AMD64RMOp op, OperandSize size, Value input) {
         Variable result = newVariable(kind);
-        append(new AMD64UnaryRMOp(op, size, result, asAllocatable(input)));
+        append(new AMD64Unary.RMOp(op, size, result, asAllocatable(input)));
         return result;
     }
 
     private AllocatableValue emitConvertOp(LIRKind kind, AMD64MROp op, OperandSize size, Value input) {
         Variable result = newVariable(kind);
-        append(new AMD64UnaryMROp(op, size, result, asAllocatable(input)));
+        append(new AMD64Unary.MROp(op, size, result, asAllocatable(input)));
         return result;
     }
 
@@ -1006,13 +1001,13 @@
             assert inputVal.getKind() == Kind.Long;
             Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
             long mask = CodeUtil.mask(fromBits);
-            append(new AMD64BinaryPatchOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask)));
+            append(new AMD64Binary.DataOp(AND.getRMOpcode(QWORD), QWORD, result, asAllocatable(inputVal), JavaConstant.forLong(mask)));
             return result;
         } else {
             assert inputVal.getKind().getStackKind() == Kind.Int;
             Variable result = newVariable(LIRKind.derive(inputVal).changeType(Kind.Int));
             int mask = (int) CodeUtil.mask(fromBits);
-            append(new AMD64BinaryPatchOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask)));
+            append(new AMD64Binary.DataOp(AND.getRMOpcode(DWORD), DWORD, result, asAllocatable(inputVal), JavaConstant.forInt(mask)));
             if (toBits > 32) {
                 Variable longResult = newVariable(LIRKind.derive(inputVal).changeType(Kind.Long));
                 emitMove(longResult, result);
@@ -1047,9 +1042,9 @@
     public Variable emitBitCount(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64UnaryRMOp(POPCNT, DWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(POPCNT, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64UnaryRMOp(POPCNT, QWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(POPCNT, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1057,7 +1052,7 @@
     @Override
     public Variable emitBitScanForward(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
-        append(new AMD64UnaryRMOp(BSF, QWORD, result, asAllocatable(value)));
+        append(new AMD64Unary.RMOp(BSF, QWORD, result, asAllocatable(value)));
         return result;
     }
 
@@ -1065,9 +1060,9 @@
     public Variable emitBitScanReverse(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64UnaryRMOp(BSR, DWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(BSR, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64UnaryRMOp(BSR, QWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(BSR, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1075,9 +1070,9 @@
     public Value emitCountLeadingZeros(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64UnaryRMOp(LZCNT, DWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(LZCNT, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64UnaryRMOp(LZCNT, QWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(LZCNT, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1085,9 +1080,9 @@
     public Value emitCountTrailingZeros(Value value) {
         Variable result = newVariable(LIRKind.derive(value).changeType(Kind.Int));
         if (value.getKind().getStackKind() == Kind.Int) {
-            append(new AMD64UnaryRMOp(TZCNT, DWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(TZCNT, DWORD, result, asAllocatable(value)));
         } else {
-            append(new AMD64UnaryRMOp(TZCNT, QWORD, result, asAllocatable(value)));
+            append(new AMD64Unary.RMOp(TZCNT, QWORD, result, asAllocatable(value)));
         }
         return result;
     }
@@ -1097,10 +1092,10 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Float:
-                append(new AMD64BinaryPatchOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16));
+                append(new AMD64Binary.DataOp(SSEOp.AND, PS, result, asAllocatable(input), JavaConstant.forFloat(Float.intBitsToFloat(0x7FFFFFFF)), 16));
                 break;
             case Double:
-                append(new AMD64BinaryPatchOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16));
+                append(new AMD64Binary.DataOp(SSEOp.AND, PD, result, asAllocatable(input), JavaConstant.forDouble(Double.longBitsToDouble(0x7FFFFFFFFFFFFFFFL)), 16));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
@@ -1113,10 +1108,10 @@
         Variable result = newVariable(LIRKind.derive(input));
         switch (input.getKind()) {
             case Float:
-                append(new AMD64UnaryRMOp(SSEOp.SQRT, SS, result, asAllocatable(input)));
+                append(new AMD64Unary.RMOp(SSEOp.SQRT, SS, result, asAllocatable(input)));
                 break;
             case Double:
-                append(new AMD64UnaryRMOp(SSEOp.SQRT, SD, result, asAllocatable(input)));
+                append(new AMD64Unary.RMOp(SSEOp.SQRT, SD, result, asAllocatable(input)));
                 break;
             default:
                 throw GraalInternalError.shouldNotReachHere();
--- a/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.compiler.amd64/src/com/oracle/graal/compiler/amd64/AMD64NodeLIRBuilder.java	Mon Mar 23 16:11:48 2015 +0100
@@ -214,13 +214,13 @@
                 return null;
             }
             return builder -> {
-                gen.append(new AMD64CompareMemoryConstOp(AMD64MIOp.TEST, size, makeAddress(access), constant, getState(access)));
+                gen.append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.TEST, size, makeAddress(access), (int) constant.asLong(), getState(access)));
                 gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
                 return null;
             };
         } else {
             return builder -> {
-                gen.append(new AMD64CompareMemoryOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), makeAddress(access), getState(access)));
+                gen.append(new AMD64BinaryConsumer.MemoryRMOp(AMD64RMOp.TEST, size, gen.asAllocatable(operand(value)), makeAddress(access), getState(access)));
                 gen.append(new BranchOp(Condition.EQ, trueLabel, falseLabel, trueLabelProbability));
                 return null;
             };
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Mar 23 16:11:48 2015 +0100
@@ -46,7 +46,6 @@
 import com.oracle.graal.lir.phases.*;
 import com.oracle.graal.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext;
 import com.oracle.graal.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
-import com.oracle.graal.lir.profiling.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Mar 23 16:11:48 2015 +0100
@@ -37,9 +37,11 @@
  */
 public class Graph {
 
-    static class Options {
+    public static class Options {
         @Option(help = "Verify graphs often during compilation when assertions are turned on", type = OptionType.Debug)//
         public static final OptionValue<Boolean> VerifyGraalGraphs = new OptionValue<>(true);
+        @Option(help = "Perform expensive verification of graph inputs, usages, successors and predecessors", type = OptionType.Debug)//
+        public static final OptionValue<Boolean> VerifyGraalGraphEdges = new OptionValue<>(false);
     }
 
     public final String name;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Mar 23 16:11:48 2015 +0100
@@ -847,9 +847,30 @@
     protected void afterClone(@SuppressWarnings("unused") Node other) {
     }
 
+    public boolean verifyInputs() {
+        for (Node input : inputs()) {
+            assertFalse(input.isDeleted(), "input was deleted");
+            assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph");
+        }
+        return true;
+    }
+
     public boolean verify() {
         assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
         assertTrue(graph() != null, "null graph");
+        if (Options.VerifyGraalGraphEdges.getValue()) {
+            verifyEdges();
+        }
+        return true;
+    }
+
+    /**
+     * Perform expensive verification of inputs, usages, predecessors and successors.
+     *
+     * @return true
+     */
+    public boolean verifyEdges() {
+        verifyInputs();
         for (Node input : inputs()) {
             assertTrue(input.usages().contains(this), "missing usage in input %s", input);
         }
@@ -864,7 +885,7 @@
             while (iterator.hasNext()) {
                 Position pos = iterator.nextPosition();
                 if (pos.get(usage) == this && pos.getInputType() != InputType.Unchecked) {
-                    assert isAllowedUsageType(pos.getInputType()) : "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")";
+                    assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")");
                 }
             }
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Mar 23 16:11:48 2015 +0100
@@ -335,8 +335,12 @@
 
     @Override
     @SuppressWarnings("unchecked")
-    public <A> A[] toArray(A[] template) {
-        return (A[]) Arrays.copyOf(nodes, size, template.getClass());
+    public <A> A[] toArray(A[] a) {
+        if (a.length >= size) {
+            System.arraycopy(nodes, 0, a, 0, size);
+            return a;
+        }
+        return (A[]) Arrays.copyOf(nodes, size, a.getClass());
     }
 
     @Override
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderConfiguration.java	Mon Mar 23 16:11:48 2015 +0100
@@ -168,7 +168,7 @@
      * {@link InvocationPlugins} in the copy.
      */
     public GraphBuilderConfiguration copy() {
-        Plugins newPlugins = new Plugins(new InvocationPlugins(plugins.getInvocationPlugins()));
+        Plugins newPlugins = new Plugins(plugins);
         GraphBuilderConfiguration result = new GraphBuilderConfiguration(eagerResolving, omitAllExceptionEdges, debugInfoMode, skippedExceptionTypes, doLivenessAnalysis, newPlugins);
         result.useProfiling = useProfiling;
         return result;
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Mon Mar 23 16:11:48 2015 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -60,15 +59,15 @@
         boolean isIntrinsic();
     }
 
-    <T extends ControlSinkNode> T append(T fixed);
-
-    <T extends ControlSplitNode> T append(T fixed);
+    <T extends ValueNode> T append(T value);
 
-    <T extends FixedWithNextNode> T append(T fixed);
-
-    <T extends FloatingNode> T append(T value);
-
-    <T extends ValueNode> T append(T value);
+    /**
+     * Adds the given floating node to the graph and also adds recursively all referenced inputs.
+     *
+     * @param value the floating node to be added to the graph
+     * @return either the node added or an equivalent node
+     */
+    <T extends ValueNode> T recursiveAppend(T value);
 
     StampProvider getStampProvider();
 
@@ -125,17 +124,6 @@
      */
     Replacement getReplacement();
 
-    /**
-     * @see GuardingPiNode#nullCheckedValue(ValueNode)
-     */
-    static ValueNode nullCheckedValue(GraphBuilderContext builder, ValueNode value) {
-        ValueNode nonNullValue = GuardingPiNode.nullCheckedValue(value);
-        if (nonNullValue != value) {
-            builder.append((FixedWithNextNode) nonNullValue);
-        }
-        return nonNullValue;
-    }
-
     boolean eagerResolving();
 
     BailoutException bailout(String string);
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugin.java	Mon Mar 23 16:11:48 2015 +0100
@@ -26,6 +26,7 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -36,43 +37,43 @@
     /**
      * @see #execute
      */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
-        throw invalidHandler(b, targetMethod);
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+        throw invalidHandler(b, targetMethod, receiver);
     }
 
     /**
      * @see #execute
      */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
-        throw invalidHandler(b, targetMethod, arg);
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+        throw invalidHandler(b, targetMethod, receiver, arg);
     }
 
     /**
      * @see #execute
      */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2) {
-        throw invalidHandler(b, targetMethod, arg1, arg2);
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
+        throw invalidHandler(b, targetMethod, receiver, arg1, arg2);
     }
 
     /**
      * @see #execute
      */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
-        throw invalidHandler(b, targetMethod, arg1, arg2, arg3);
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3) {
+        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3);
     }
 
     /**
      * @see #execute
      */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
-        throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4);
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
+        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4);
     }
 
     /**
      * @see #execute
      */
-    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
-        throw invalidHandler(b, targetMethod, arg1, arg2, arg3, arg4, arg5);
+    default boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4, ValueNode arg5) {
+        throw invalidHandler(b, targetMethod, receiver, arg1, arg2, arg3, arg4, arg5);
     }
 
     default ResolvedJavaMethod getSubstitute() {
@@ -84,30 +85,52 @@
      * {@code apply(...)} method that matches the number of arguments.
      *
      * @param targetMethod the method for which plugin is being applied
+     * @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
+     * @param args the remaining arguments
      * @return {@code true} if the plugin handled the invocation of {@code targetMethod}
      *         {@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 b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, ValueNode[] args) {
-        if (args.length == 0) {
-            return plugin.apply(b, targetMethod);
-        } else if (args.length == 1) {
-            return plugin.apply(b, targetMethod, args[0]);
-        } else if (args.length == 2) {
-            return plugin.apply(b, targetMethod, args[0], args[1]);
-        } else if (args.length == 3) {
-            return plugin.apply(b, targetMethod, args[0], args[1], args[2]);
-        } else if (args.length == 4) {
-            return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3]);
-        } else if (args.length == 5) {
-            return plugin.apply(b, targetMethod, args[0], args[1], args[2], args[3], args[4]);
+    static boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin plugin, Receiver receiver, ValueNode[] args) {
+        if (receiver != null) {
+            assert !targetMethod.isStatic();
+            assert args.length > 0;
+            if (args.length == 1) {
+                return plugin.apply(b, targetMethod, receiver);
+            } else if (args.length == 2) {
+                return plugin.apply(b, targetMethod, receiver, args[1]);
+            } else if (args.length == 3) {
+                return plugin.apply(b, targetMethod, receiver, args[1], args[2]);
+            } else if (args.length == 4) {
+                return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3]);
+            } else if (args.length == 5) {
+                return plugin.apply(b, targetMethod, receiver, args[1], args[2], args[3], args[4]);
+            } else {
+                throw plugin.invalidHandler(b, targetMethod, receiver, args);
+            }
         } else {
-            throw plugin.invalidHandler(b, targetMethod, args);
+            assert targetMethod.isStatic();
+            if (args.length == 0) {
+                return plugin.apply(b, targetMethod, null);
+            } else if (args.length == 1) {
+                return plugin.apply(b, targetMethod, null, args[0]);
+            } else if (args.length == 2) {
+                return plugin.apply(b, targetMethod, null, args[0], args[1]);
+            } else if (args.length == 3) {
+                return plugin.apply(b, targetMethod, null, args[0], args[1], args[2]);
+            } else if (args.length == 4) {
+                return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3]);
+            } else if (args.length == 5) {
+                return plugin.apply(b, targetMethod, null, args[0], args[1], args[2], args[3], args[4]);
+            } else {
+                throw plugin.invalidHandler(b, targetMethod, receiver, args);
+            }
+
         }
     }
 
-    default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode... args) {
+    default Error invalidHandler(@SuppressWarnings("unused") GraphBuilderContext b, ResolvedJavaMethod targetMethod, @SuppressWarnings("unused") Receiver receiver, ValueNode... args) {
         return new GraalInternalError("Invocation plugin for %s does not handle invocations with %d arguments", targetMethod.format("%H.%n(%p)"), args.length);
     }
 
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Mon Mar 23 16:11:48 2015 +0100
@@ -30,7 +30,10 @@
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.Node;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.type.*;
 
 /**
  * Manages a set of {@link InvocationPlugin}s.
@@ -38,14 +41,24 @@
 public class InvocationPlugins {
 
     /**
-     * Sentinel class for use with
+     * Access to the receiver in an {@link InvocationPlugin} for a non-static method. The class
+     * literal for this interface must be used with
      * {@link InvocationPlugins#register(InvocationPlugin, Class, String, Class...)} to denote the
-     * receiver argument for a non-static method.
+     * receiver argument for such a non-static method.
      */
-    public static final class Receiver {
-        private Receiver() {
-            throw GraalInternalError.shouldNotReachHere();
-        }
+    public interface Receiver {
+        /**
+         * Gets the receiver value, null checking it first if necessary.
+         *
+         * @return the receiver value with a {@linkplain StampTool#isPointerNonNull(ValueNode)
+         *         non-null} stamp
+         */
+        ValueNode get();
+
+        /**
+         * Determines if the receiver is constant.
+         */
+        boolean isConstant();
     }
 
     /**
@@ -342,11 +355,12 @@
                     Class<?>[] sig = method.getParameterTypes();
                     assert sig[0] == GraphBuilderContext.class;
                     assert sig[1] == ResolvedJavaMethod.class;
-                    assert Arrays.asList(Arrays.copyOfRange(sig, 2, sig.length)).stream().allMatch(c -> c == ValueNode.class);
-                    while (sigs.size() < sig.length - 1) {
+                    assert sig[2] == Receiver.class;
+                    assert Arrays.asList(Arrays.copyOfRange(sig, 3, sig.length)).stream().allMatch(c -> c == ValueNode.class);
+                    while (sigs.size() < sig.length - 2) {
                         sigs.add(null);
                     }
-                    sigs.set(sig.length - 2, sig);
+                    sigs.set(sig.length - 3, 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),
@@ -360,7 +374,7 @@
                 assert !p.registrations.contains(method) : "a plugin is already registered for " + method;
                 p = p.parent;
             }
-            int arguments = method.argumentTypes.length;
+            int arguments = method.isStatic ? method.argumentTypes.length : method.argumentTypes.length - 1;
             assert arguments < SIGS.length : format("need to extend %s to support method with %d arguments: %s", InvocationPlugin.class.getSimpleName(), arguments, method);
             for (Method m : plugin.getClass().getDeclaredMethods()) {
                 if (m.getName().equals("apply")) {
@@ -381,4 +395,18 @@
     public int size() {
         return registrations.size();
     }
+
+    /**
+     * Checks a set of nodes added to the graph by an {@link InvocationPlugin}.
+     *
+     * @param b the graph builder that applied the plugin
+     * @param plugin a plugin that was just applied
+     * @param newNodes the nodes added to the graph by {@code plugin}
+     * @throws AssertionError if any check fail
+     */
+    public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
+        if (parent != null) {
+            parent.checkNewNodes(b, plugin, newNodes);
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBinaryConsumer.java	Mon Mar 23 16:11:48 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.hotspot.amd64;
+
+import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+
+public class AMD64HotSpotBinaryConsumer {
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one {@link HotSpotConstant}
+     * operand.
+     */
+    public static class ConstOp extends AMD64BinaryConsumer.ConstOp {
+        public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
+
+        protected final HotSpotConstant c;
+
+        public ConstOp(AMD64MIOp opcode, AllocatableValue x, HotSpotConstant c) {
+            super(TYPE, opcode, DWORD, x, asImm32(c));
+            this.c = c;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            assert crb.target.inlineObjects || !(c instanceof HotSpotObjectConstant);
+            crb.recordInlineDataInCode(c);
+            super.emitCode(crb, masm);
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AMD64AddressValue memory} operand and one
+     * {@link HotSpotConstant} operand.
+     */
+    public static class MemoryConstOp extends AMD64BinaryConsumer.MemoryConstOp {
+        public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class);
+
+        protected final HotSpotConstant c;
+
+        public MemoryConstOp(AMD64MIOp opcode, AMD64AddressValue x, HotSpotConstant c, LIRFrameState state) {
+            super(TYPE, opcode, DWORD, x, asImm32(c), state);
+            this.c = c;
+
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            assert crb.target.inlineObjects || !(c instanceof HotSpotObjectConstant);
+            crb.recordInlineDataInCode(c);
+            super.emitCode(crb, masm);
+        }
+    }
+
+    private static int asImm32(HotSpotConstant c) {
+        assert c.isCompressed();
+        if (c instanceof HotSpotMetaspaceConstant) {
+            return (int) ((HotSpotMetaspaceConstant) c).rawValue();
+        } else {
+            assert c instanceof HotSpotObjectConstant;
+            return 0xDEADDEAD;
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +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.hotspot.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64HotSpotCompareConstOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64HotSpotCompareConstOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCompareConstOp.class);
-
-    @Opcode private final AMD64MIOp opcode;
-
-    @Use({REG, STACK}) protected AllocatableValue x;
-    protected HotSpotConstant y;
-
-    public AMD64HotSpotCompareConstOp(AMD64MIOp opcode, AllocatableValue x, HotSpotConstant y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.x = x;
-        this.y = y;
-
-        assert y.isCompressed();
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        int imm32;
-        if (y instanceof HotSpotMetaspaceConstant) {
-            imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue();
-        } else {
-            assert y instanceof HotSpotObjectConstant;
-            imm32 = 0xDEADDEAD;
-        }
-
-        crb.recordInlineDataInCode(y);
-        if (isRegister(x)) {
-            opcode.emit(masm, DWORD, asRegister(x), imm32);
-        } else {
-            assert isStackSlot(x);
-            opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32);
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCompareMemoryConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +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.hotspot.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64HotSpotCompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
-    public static final LIRInstructionClass<AMD64HotSpotCompareMemoryConstOp> TYPE = LIRInstructionClass.create(AMD64HotSpotCompareMemoryConstOp.class);
-
-    @Opcode private final AMD64MIOp opcode;
-
-    @Use({COMPOSITE}) protected AMD64AddressValue x;
-    protected HotSpotConstant y;
-
-    @State protected LIRFrameState state;
-
-    public AMD64HotSpotCompareMemoryConstOp(AMD64MIOp opcode, AMD64AddressValue x, HotSpotConstant y, LIRFrameState state) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.x = x;
-        this.y = y;
-        this.state = state;
-
-        assert y.isCompressed();
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        int imm32;
-        if (y instanceof HotSpotMetaspaceConstant) {
-            imm32 = (int) ((HotSpotMetaspaceConstant) y).rawValue();
-        } else {
-            assert y instanceof HotSpotObjectConstant;
-            imm32 = 0xDEADDEAD;
-        }
-
-        crb.recordInlineDataInCode(y);
-        if (isRegister(x)) {
-            opcode.emit(masm, DWORD, asRegister(x), imm32);
-        } else {
-            assert isStackSlot(x);
-            opcode.emit(masm, DWORD, (AMD64Address) crb.asAddress(x), imm32);
-        }
-    }
-
-    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-        if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
-            state = nullCheckState;
-            return true;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotComparePatchOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +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.hotspot.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64HotSpotComparePatchOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64HotSpotComparePatchOp> TYPE = LIRInstructionClass.create(AMD64HotSpotComparePatchOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Use({REG}) protected AllocatableValue x;
-    protected HotSpotConstant y;
-
-    public AMD64HotSpotComparePatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, HotSpotConstant y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Address addr = (AMD64Address) crb.recordDataReferenceInCode(y, size.getBytes());
-        opcode.emit(masm, size, asRegister(x), addr);
-    }
-}
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Mon Mar 23 16:11:48 2015 +0100
@@ -34,6 +34,9 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
 import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
 import com.oracle.graal.compiler.amd64.*;
 import com.oracle.graal.compiler.common.*;
@@ -42,7 +45,6 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.HotSpotVMConfig.CompressEncoding;
-import com.oracle.graal.hotspot.amd64.AMD64HotSpotMove.HotSpotStoreConstantOp;
 import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.stubs.*;
@@ -53,9 +55,7 @@
 import com.oracle.graal.lir.amd64.AMD64ControlFlow.CondMoveOp;
 import com.oracle.graal.lir.amd64.AMD64Move.CompareAndSwapOp;
 import com.oracle.graal.lir.amd64.AMD64Move.LeaDataOp;
-import com.oracle.graal.lir.amd64.AMD64Move.LoadOp;
 import com.oracle.graal.lir.amd64.AMD64Move.MoveFromRegOp;
-import com.oracle.graal.lir.amd64.AMD64Move.StoreOp;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.lir.gen.*;
@@ -506,22 +506,137 @@
     public Variable emitLoad(LIRKind kind, Value address, LIRFrameState state) {
         AMD64AddressValue loadAddress = asAddressValue(address);
         Variable result = newVariable(toStackKind(kind));
-        append(new LoadOp((Kind) kind.getPlatformKind(), result, loadAddress, state));
+        switch ((Kind) kind.getPlatformKind()) {
+            case Boolean:
+                append(new AMD64Unary.MemoryOp(MOVZXB, DWORD, result, loadAddress, state));
+                break;
+            case Byte:
+                append(new AMD64Unary.MemoryOp(MOVSXB, DWORD, result, loadAddress, state));
+                break;
+            case Char:
+                append(new AMD64Unary.MemoryOp(MOVZX, DWORD, result, loadAddress, state));
+                break;
+            case Short:
+                append(new AMD64Unary.MemoryOp(MOVSX, DWORD, result, loadAddress, state));
+                break;
+            case Int:
+                append(new AMD64Unary.MemoryOp(MOV, DWORD, result, loadAddress, state));
+                break;
+            case Long:
+            case Object:
+                append(new AMD64Unary.MemoryOp(MOV, QWORD, result, loadAddress, state));
+                break;
+            case Float:
+                append(new AMD64Unary.MemoryOp(MOVSS, SS, result, loadAddress, state));
+                break;
+            case Double:
+                append(new AMD64Unary.MemoryOp(MOVSD, SD, result, loadAddress, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
         return result;
     }
 
+    private void emitStoreConst(Kind kind, AMD64AddressValue address, JavaConstant value, LIRFrameState state) {
+        if (value.isNull()) {
+            assert kind == Kind.Int || kind == Kind.Long || kind == Kind.Object;
+            OperandSize size = kind == Kind.Int ? DWORD : QWORD;
+            append(new AMD64BinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, size, address, 0, state));
+        } else if (value instanceof HotSpotConstant) {
+            HotSpotConstant c = (HotSpotConstant) value;
+            if (c.isCompressed()) {
+                assert kind == Kind.Int;
+                if (!target().inlineObjects && c instanceof HotSpotObjectConstant) {
+                    emitStore(kind, address, asAllocatable(value), state);
+                } else {
+                    append(new AMD64HotSpotBinaryConsumer.MemoryConstOp(AMD64MIOp.MOV, address, c, state));
+                }
+            } else {
+                emitStore(kind, address, asAllocatable(value), state);
+            }
+        } else {
+            AMD64MIOp op = AMD64MIOp.MOV;
+            OperandSize size;
+            long imm;
+
+            switch (kind) {
+                case Boolean:
+                case Byte:
+                    op = AMD64MIOp.MOVB;
+                    size = BYTE;
+                    imm = value.asInt();
+                    break;
+                case Char:
+                case Short:
+                    size = WORD;
+                    imm = value.asInt();
+                    break;
+                case Int:
+                    size = DWORD;
+                    imm = value.asInt();
+                    break;
+                case Long:
+                    size = QWORD;
+                    imm = value.asLong();
+                    break;
+                case Float:
+                    size = DWORD;
+                    imm = Float.floatToRawIntBits(value.asFloat());
+                    break;
+                case Double:
+                    size = QWORD;
+                    imm = Double.doubleToRawLongBits(value.asDouble());
+                    break;
+                default:
+                    throw GraalInternalError.shouldNotReachHere("unexpected kind " + kind);
+            }
+
+            if (NumUtil.isInt(imm)) {
+                append(new AMD64BinaryConsumer.MemoryConstOp(op, size, address, (int) imm, state));
+            } else {
+                emitStore(kind, address, asAllocatable(value), state);
+            }
+        }
+    }
+
+    private void emitStore(Kind kind, AMD64AddressValue address, AllocatableValue value, LIRFrameState state) {
+        switch (kind) {
+            case Boolean:
+            case Byte:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVB, BYTE, address, value, state));
+                break;
+            case Char:
+            case Short:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, WORD, address, value, state));
+                break;
+            case Int:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, DWORD, address, value, state));
+                break;
+            case Long:
+            case Object:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOV, QWORD, address, value, state));
+                break;
+            case Float:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSS, SS, address, value, state));
+                break;
+            case Double:
+                append(new AMD64BinaryConsumer.MemoryMROp(AMD64MROp.MOVSD, SD, address, value, state));
+                break;
+            default:
+                throw GraalInternalError.shouldNotReachHere();
+        }
+    }
+
     @Override
-    public void emitStore(LIRKind kind, Value address, Value inputVal, LIRFrameState state) {
+    public void emitStore(LIRKind lirKind, Value address, Value input, LIRFrameState state) {
         AMD64AddressValue storeAddress = asAddressValue(address);
-        if (isConstant(inputVal)) {
-            JavaConstant c = asConstant(inputVal);
-            if (canStoreConstant(c)) {
-                append(new HotSpotStoreConstantOp((Kind) kind.getPlatformKind(), storeAddress, c, state));
-                return;
-            }
+        Kind kind = (Kind) lirKind.getPlatformKind();
+        if (isConstant(input)) {
+            emitStoreConst(kind, storeAddress, asConstant(input), state);
+        } else {
+            emitStore(kind, storeAddress, asAllocatable(input), state);
         }
-        Variable input = load(inputVal);
-        append(new StoreOp((Kind) kind.getPlatformKind(), storeAddress, input, state));
     }
 
     @Override
@@ -628,17 +743,17 @@
     @Override
     protected void emitCompareOp(PlatformKind cmpKind, Variable left, Value right) {
         if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(right)) {
-            append(new AMD64CompareOp(TEST, DWORD, left, left));
+            append(new AMD64BinaryConsumer.Op(TEST, DWORD, left, left));
         } else if (right instanceof HotSpotConstant) {
             HotSpotConstant c = (HotSpotConstant) right;
 
             boolean isImmutable = GraalOptions.ImmutableCode.getValue();
             boolean generatePIC = GraalOptions.GeneratePIC.getValue();
             if (c.isCompressed() && !(isImmutable && generatePIC)) {
-                append(new AMD64HotSpotCompareConstOp(CMP.getMIOpcode(DWORD, false), left, c));
+                append(new AMD64HotSpotBinaryConsumer.ConstOp(CMP.getMIOpcode(DWORD, false), left, c));
             } else {
                 OperandSize size = c.isCompressed() ? DWORD : QWORD;
-                append(new AMD64HotSpotComparePatchOp(CMP.getRMOpcode(size), size, left, c));
+                append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, c));
             }
         } else {
             super.emitCompareOp(cmpKind, left, right);
@@ -648,11 +763,11 @@
     @Override
     protected boolean emitCompareMemoryConOp(OperandSize size, JavaConstant a, AMD64AddressValue b, LIRFrameState state) {
         if (a.isNull()) {
-            append(new AMD64CompareMemoryConstOp(CMP.getMIOpcode(size, true), size, b, PrimitiveConstant.INT_0, state));
+            append(new AMD64BinaryConsumer.MemoryConstOp(CMP, size, b, 0, state));
             return true;
         } else if (a instanceof HotSpotConstant && size == DWORD) {
             assert ((HotSpotConstant) a).isCompressed();
-            append(new AMD64HotSpotCompareMemoryConstOp(CMP.getMIOpcode(size, false), b, (HotSpotConstant) a, state));
+            append(new AMD64HotSpotBinaryConsumer.MemoryConstOp(CMP.getMIOpcode(size, false), b, (HotSpotConstant) a, state));
             return true;
         } else {
             return super.emitCompareMemoryConOp(size, a, b, state);
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotMove.java	Mon Mar 23 16:11:48 2015 +0100
@@ -38,7 +38,6 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.amd64.*;
-import com.oracle.graal.lir.amd64.AMD64Move.StoreConstantOp;
 import com.oracle.graal.lir.asm.*;
 
 public class AMD64HotSpotMove {
@@ -146,44 +145,6 @@
         }
     }
 
-    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(TYPE, kind, address, input, state);
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (input.isNull() && kind == Kind.Int) {
-                // compressed null
-                masm.movl(address.toAddress(), 0);
-            } else if (input instanceof HotSpotObjectConstant) {
-                HotSpotObjectConstant c = (HotSpotObjectConstant) input;
-                if (c.isCompressed() && crb.target.inlineObjects) {
-                    // compressed oop
-                    crb.recordInlineDataInCode(input);
-                    masm.movl(address.toAddress(), 0xDEADDEAD);
-                } else {
-                    // uncompressed oop
-                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                }
-            } else if (input instanceof HotSpotMetaspaceConstant) {
-                if (input.getKind() == Kind.Int) {
-                    // compressed metaspace pointer
-                    crb.recordInlineDataInCode(input);
-                    masm.movl(address.toAddress(), input.asInt());
-                } else {
-                    // uncompressed metaspace pointer
-                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                }
-            } else {
-                // primitive value
-                super.emitMemAccess(crb, masm);
-            }
-        }
-    }
-
     public static final class CompressPointer extends AMD64LIRInstruction {
         public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
 
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.test;
 
-import static com.oracle.graal.nodes.spi.Replacements.*;
-
 import java.io.*;
 import java.lang.reflect.*;
 import java.security.*;
@@ -34,10 +32,16 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.bridge.CompilerToVM.CodeInstallResult;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
+import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.StructuredGraph.*;
+import com.oracle.graal.phases.*;
 
 /**
  * Tests the intrinsification of certain crypto methods.
@@ -58,44 +62,51 @@
         return installedCode;
     }
 
-    @Test
-    public void testEncryptSubstitution() throws Exception {
-        Assume.assumeTrue(SELF_RECURSIVE_INTRINSICS_ENABLED);
+    SecretKey aesKey;
+    SecretKey desKey;
+    byte[] input;
+    ByteArrayOutputStream aesExpected = new ByteArrayOutputStream();
+    ByteArrayOutputStream desExpected = new ByteArrayOutputStream();
 
+    public HotSpotCryptoSubstitutionTest() throws Exception {
         byte[] seed = {0x4, 0x7, 0x1, 0x1};
         SecureRandom random = new SecureRandom(seed);
         KeyGenerator aesKeyGen = KeyGenerator.getInstance("AES");
         KeyGenerator desKeyGen = KeyGenerator.getInstance("DESede");
         aesKeyGen.init(128, random);
         desKeyGen.init(168, random);
-        SecretKey aesKey = aesKeyGen.generateKey();
-        SecretKey desKey = desKeyGen.generateKey();
-        byte[] input = readClassfile16(getClass());
+        aesKey = aesKeyGen.generateKey();
+        desKey = desKeyGen.generateKey();
+        input = readClassfile16(getClass());
+
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
+        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
 
-        ByteArrayOutputStream aesExpected = new ByteArrayOutputStream();
-        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
-        aesExpected.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding"));
+        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding"));
+    }
 
+    @Test
+    public void testAESCryptIntrinsics() throws Exception {
         if (compileAndInstall("com.sun.crypto.provider.AESCrypt", "encryptBlock", "decryptBlock")) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
-            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
-            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
             Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
         }
+    }
 
-        ByteArrayOutputStream desExpected = new ByteArrayOutputStream();
-        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input));
-        desExpected.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input));
-
+    @Test
+    public void testCipherBlockChainingIntrinsics() throws Exception {
         if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", "encrypt", "decrypt")) {
             ByteArrayOutputStream actual = new ByteArrayOutputStream();
-            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding", input));
-            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding", input));
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
+            actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));
             Assert.assertArrayEquals(aesExpected.toByteArray(), actual.toByteArray());
 
             actual.reset();
-            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding", input));
-            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding", input));
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/NoPadding"));
+            actual.write(runEncryptDecrypt(desKey, "DESede/CBC/PKCS5Padding"));
             Assert.assertArrayEquals(desExpected.toByteArray(), actual.toByteArray());
         }
     }
@@ -114,9 +125,13 @@
             Method method = lookup(className, methodName);
             if (method != null) {
                 ResolvedJavaMethod installedCodeOwner = getMetaAccess().lookupJavaMethod(method);
-                StructuredGraph subst = getReplacements().getMethodSubstitution(installedCodeOwner);
-                if (subst != null) {
-                    StructuredGraph graph = subst.copy();
+                ResolvedJavaMethod substMethod = getReplacements().getMethodSubstitutionMethod(installedCodeOwner);
+                if (substMethod != null) {
+                    StructuredGraph graph = new StructuredGraph(substMethod, AllowAssumptions.YES);
+                    Plugins plugins = new Plugins(((HotSpotProviders) getProviders()).getGraphBuilderPlugins());
+                    GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+                    IntrinsicContext initialReplacementContext = new IntrinsicContext(installedCodeOwner, substMethod, null, -2);
+                    new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
                     Assert.assertNotNull(getCode(installedCodeOwner, graph, true));
                     atLeastOneCompiled = true;
                 } else {
@@ -191,7 +206,7 @@
         return classFile;
     }
 
-    public byte[] runEncryptDecrypt(SecretKey key, String algorithm, byte[] input) throws Exception {
+    public byte[] runEncryptDecrypt(SecretKey key, String algorithm) throws Exception {
         byte[] indata = input.clone();
         byte[] cipher = encrypt(indata, key, algorithm);
         byte[] plain = decrypt(cipher, key, algorithm);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon Mar 23 16:11:48 2015 +0100
@@ -290,7 +290,7 @@
             final int processedBytes = (int) (InlinedBytecodes.getCurrentValue() - previousInlinedBytecodes);
 
             // Log a compilation event.
-            if (compilationEvent.shouldWrite()) {
+            if (compilationEvent.shouldWrite() && installedCode != null) {
                 compilationEvent.setMethod(method.format("%H.%n(%p)"));
                 compilationEvent.setCompileId(getId());
                 compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompileTheWorld.java	Mon Mar 23 16:11:48 2015 +0100
@@ -31,16 +31,21 @@
 import java.lang.reflect.*;
 import java.net.*;
 import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
 import java.util.jar.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.bytecode.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.CompilerThreadFactory.DebugConfigAccess;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.options.OptionUtils.OptionConsumer;
 import com.oracle.graal.options.OptionValue.OverrideScope;
+import com.oracle.graal.printer.*;
 import com.oracle.graal.replacements.*;
 
 /**
@@ -69,6 +74,9 @@
                        "to disable inlining and partial escape analysis specify '-PartialEscapeAnalysis -Inline'. " +
                        "The format for each option is the same as on the command line just without the '-G:' prefix.", type = OptionType.Debug)
         public static final OptionValue<String> CompileTheWorldConfig = new OptionValue<>(null);
+
+        @Option(help = "Last class to consider when using -XX:+CompileTheWorld", type = OptionType.Debug)
+        public static final OptionValue<Boolean> CompileTheWorldMultiThreaded = new OptionValue<>(false);
         // @formatter:on
 
         /**
@@ -98,9 +106,7 @@
      * </pre>
      */
     @SuppressWarnings("serial")
-    public static class Config extends HashMap<OptionValue<?>, Object> implements AutoCloseable, OptionConsumer {
-        OverrideScope scope;
-
+    public static class Config extends HashMap<OptionValue<?>, Object> implements OptionConsumer {
         /**
          * Creates a {@link Config} object by parsing a set of space separated override options.
          *
@@ -120,20 +126,10 @@
 
         /**
          * Applies the overrides represented by this object. The overrides are in effect until
-         * {@link #close()} is called on this object.
+         * {@link OverrideScope#close()} is called on the returned object.
          */
-        Config apply() {
-            assert scope == null;
-            scope = OptionValue.override(this);
-            return this;
-        }
-
-        public void close() {
-            assert scope != null;
-            scope.close();
-
-            scope = null;
-
+        OverrideScope apply() {
+            return OptionValue.override(this);
         }
 
         public void set(OptionDescriptor desc, Object value) {
@@ -155,13 +151,15 @@
 
     // Counters
     private int classFileCounter = 0;
-    private int compiledMethodsCounter = 0;
-    private long compileTime = 0;
-    private long memoryUsed = 0;
+    private AtomicLong compiledMethodsCounter = new AtomicLong();
+    private AtomicLong compileTime = new AtomicLong();
+    private AtomicLong memoryUsed = new AtomicLong();
 
     private boolean verbose;
     private final Config config;
 
+    private ThreadPoolExecutor threadPool;
+
     /**
      * Creates a compile-the-world instance.
      *
@@ -177,11 +175,11 @@
         this.config = config;
 
         // We don't want the VM to exit when a method fails to compile...
-        config.put(ExitVMOnException, false);
+        config.putIfAbsent(ExitVMOnException, false);
 
         // ...but we want to see exceptions.
-        config.put(PrintBailout, true);
-        config.put(PrintStackTraceOnException, true);
+        config.putIfAbsent(PrintBailout, true);
+        config.putIfAbsent(PrintStackTraceOnException, true);
     }
 
     /**
@@ -230,12 +228,23 @@
      * Compiles all methods in all classes in the Zip/Jar files passed.
      *
      * @param fileList {@link File#pathSeparator} separated list of Zip/Jar files to compile
-     * @throws Throwable
+     * @throws IOException
      */
-    private void compile(String fileList) throws Throwable {
+    private void compile(String fileList) throws IOException {
         final String[] entries = fileList.split(File.pathSeparator);
+        long start = System.currentTimeMillis();
 
-        try (AutoCloseable s = config.apply()) {
+        if (Options.CompileTheWorldMultiThreaded.getValue()) {
+            CompilerThreadFactory factory = new CompilerThreadFactory("CompileTheWorld", new DebugConfigAccess() {
+                public GraalDebugConfig getDebugConfig() {
+                    return DebugEnvironment.initialize(System.out);
+                }
+            });
+            int availableProcessors = Runtime.getRuntime().availableProcessors();
+            threadPool = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
+        }
+
+        try (OverrideScope s = config.apply()) {
             for (int i = 0; i < entries.length; i++) {
                 final String entry = entries[i];
 
@@ -312,8 +321,22 @@
             }
         }
 
+        if (threadPool != null) {
+            while (threadPool.getCompletedTaskCount() != threadPool.getTaskCount()) {
+                System.out.println("CompileTheWorld : Waiting for " + (threadPool.getTaskCount() - threadPool.getCompletedTaskCount()) + " compiles");
+                try {
+                    threadPool.awaitTermination(15, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                }
+            }
+            threadPool = null;
+        }
+
+        long elapsedTime = System.currentTimeMillis() - start;
+
         println();
-        println("CompileTheWorld : Done (%d classes, %d methods, %d ms, %d bytes of memory used)", classFileCounter, compiledMethodsCounter, compileTime, memoryUsed);
+        println("CompileTheWorld : Done (%d classes, %d methods, %d ms elapsed, %d ms compile time, %d bytes of memory used)", classFileCounter, compiledMethodsCounter.get(), elapsedTime,
+                        compileTime.get(), memoryUsed.get());
     }
 
     class CTWCompilationTask extends CompilationTask {
@@ -332,10 +355,24 @@
         }
     }
 
+    private void compileMethod(HotSpotResolvedJavaMethod method) {
+        if (threadPool != null) {
+            threadPool.submit(new Runnable() {
+                public void run() {
+                    try (OverrideScope s = config.apply()) {
+                        compileMethod(method, classFileCounter);
+                    }
+                }
+            });
+        } else {
+            compileMethod(method, classFileCounter);
+        }
+    }
+
     /**
      * Compiles a method and gathers some statistics.
      */
-    private void compileMethod(HotSpotResolvedJavaMethod method) {
+    private void compileMethod(HotSpotResolvedJavaMethod method, int counter) {
         try {
             long start = System.currentTimeMillis();
             long allocatedAtStart = getCurrentThreadAllocatedBytes();
@@ -344,12 +381,12 @@
             CompilationTask task = new CTWCompilationTask(backend, method);
             task.runCompilation();
 
-            memoryUsed += getCurrentThreadAllocatedBytes() - allocatedAtStart;
-            compileTime += (System.currentTimeMillis() - start);
-            compiledMethodsCounter++;
+            memoryUsed.getAndAdd(getCurrentThreadAllocatedBytes() - allocatedAtStart);
+            compileTime.getAndAdd(System.currentTimeMillis() - start);
+            compiledMethodsCounter.incrementAndGet();
         } catch (Throwable t) {
             // Catch everything and print a message
-            println("CompileTheWorld (%d) : Error compiling method: %s", classFileCounter, method.format("%H.%n(%p):%r"));
+            println("CompileTheWorld (%d) : Error compiling method: %s", counter, method.format("%H.%n(%p):%r"));
             t.printStackTrace(TTY.cachedOut);
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Mon Mar 23 16:11:48 2015 +0100
@@ -30,6 +30,7 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.replacements.*;
+import com.oracle.graal.hotspot.word.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.phases.util.*;
 import com.oracle.graal.replacements.*;
@@ -48,6 +49,11 @@
     }
 
     @Override
+    protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return method.getAnnotation(HotSpotOperation.class) != null || super.hasGenericInvocationPluginAnnotation(method);
+    }
+
+    @Override
     protected ResolvedJavaMethod registerMethodSubstitution(ClassReplacements cr, Executable originalMethod, Method substituteMethod) {
         final Class<?> substituteClass = substituteMethod.getDeclaringClass();
         if (substituteClass == IntegerSubstitutions.class || substituteClass == LongSubstitutions.class) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,17 +33,14 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.hotspot.*;
-import com.oracle.graal.hotspot.stubs.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
-import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 
 /**
  * HotSpot implementation of {@link ConstantReflectionProvider}.
  */
-@SuppressWarnings("unused")
 public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified {
     private static final String SystemClassName = "Ljava/lang/System;";
 
@@ -317,7 +314,7 @@
         ResolvedJavaMethod initMethod = null;
         try {
             Class<?> rjm = ResolvedJavaMethod.class;
-            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, SnippetInliningPolicy.class, FrameStateProcessing.class));
+            makeGraphMethod = metaAccess.lookupJavaMethod(ReplacementsImpl.class.getDeclaredMethod("makeGraph", rjm, Object[].class, rjm, FrameStateProcessing.class));
             initMethod = metaAccess.lookupJavaMethod(SnippetTemplate.AbstractTemplates.class.getDeclaredMethod("template", Arguments.class));
         } catch (NoSuchMethodException | SecurityException e) {
             throw new GraalInternalError(e);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Mar 23 16:11:48 2015 +0100
@@ -22,16 +22,17 @@
  */
 package com.oracle.graal.hotspot.meta;
 
-import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 
 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.compiler.common.type.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.hotspot.replacements.*;
@@ -68,7 +69,7 @@
         plugins.setParameterPlugin(new HotSpotParameterPlugin(wordTypes));
         plugins.setLoadFieldPlugin(new HotSpotLoadFieldPlugin(metaAccess, constantReflection));
         plugins.setLoadIndexedPlugin(new HotSpotLoadIndexedPlugin(wordTypes));
-        plugins.setInlineInvokePlugin(new HotSpotInlineInvokePlugin(nodeIntrinsification, replacements));
+        plugins.setInlineInvokePlugin(new DefaultInlineInvokePlugin(replacements));
         plugins.setGenericInvocationPlugin(new DefaultGenericInvocationPlugin(nodeIntrinsification, wordOperationPlugin));
 
         registerObjectPlugins(invocationPlugins);
@@ -83,14 +84,15 @@
     private static void registerObjectPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Object.class);
         r.register1("getClass", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode rcvr = receiver.get();
                 ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
                 ValueNode mirror;
-                if (objectStamp.isExactType() && objectStamp.nonNull()) {
+                if (objectStamp.isExactType() && objectStamp.nonNull() && !GraalOptions.ImmutableCode.getValue()) {
                     mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess()));
                 } else {
                     StampProvider stampProvider = b.getStampProvider();
-                    LoadHubNode hub = b.append(new LoadHubNode(stampProvider, nullCheckedValue(b, rcvr)));
+                    LoadHubNode hub = b.append(new LoadHubNode(stampProvider, rcvr));
                     mirror = b.append(new HubGetClassNode(b.getMetaAccess(), hub));
                 }
                 b.push(Kind.Object, mirror);
@@ -102,7 +104,7 @@
     private static void registerSystemPlugins(InvocationPlugins plugins, ForeignCallsProvider foreignCalls) {
         Registration r = new Registration(plugins, System.class);
         r.register0("currentTimeMillis", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_MILLIS, StampFactory.forKind(Kind.Long));
                 b.push(Kind.Long, b.append(foreignCall));
                 foreignCall.setStateAfter(b.createStateAfter());
@@ -110,7 +112,7 @@
             }
         });
         r.register0("nanoTime", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 ForeignCallNode foreignCall = new ForeignCallNode(foreignCalls, SystemSubstitutions.JAVA_TIME_NANOS, StampFactory.forKind(Kind.Long));
                 b.push(Kind.Long, b.append(foreignCall));
                 foreignCall.setStateAfter(b.createStateAfter());
@@ -122,7 +124,7 @@
     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, HotSpotVMConfig config) {
         Registration r = new Registration(plugins, Thread.class);
         r.register0("currentThread", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 CurrentJavaThreadNode thread = b.append(new CurrentJavaThreadNode(wordTypes.getWordKind()));
                 ConstantLocationNode location = b.append(new ConstantLocationNode(JAVA_THREAD_THREAD_OBJECT_LOCATION, config.threadObjectOffset));
                 boolean compressible = false;
@@ -138,9 +140,9 @@
     private static void registerStableOptionPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, StableOptionValue.class);
         r.register1("getValue", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
-                if (rcvr.isConstant() && !rcvr.isNullConstant()) {
-                    Object object = ((HotSpotObjectConstantImpl) rcvr.asConstant()).object();
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                if (receiver.isConstant()) {
+                    Object object = ((HotSpotObjectConstantImpl) receiver.get().asConstant()).object();
                     StableOptionValue<?> option = (StableOptionValue<?>) object;
                     ConstantNode value = b.append(ConstantNode.forConstant(HotSpotObjectConstantImpl.forObject(option.getValue()), b.getMetaAccess()));
                     b.push(Kind.Object, value);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +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.hotspot.meta;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
-import static java.lang.String.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
-import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
-import com.oracle.graal.hotspot.word.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.replacements.*;
-import com.oracle.graal.word.*;
-
-public final class HotSpotInlineInvokePlugin implements InlineInvokePlugin {
-    private final ReplacementsImpl replacements;
-    private final NodeIntrinsificationPhase nodeIntrinsification;
-
-    public HotSpotInlineInvokePlugin(NodeIntrinsificationPhase nodeIntrinsification, ReplacementsImpl replacements) {
-        this.nodeIntrinsification = nodeIntrinsification;
-        this.replacements = replacements;
-    }
-
-    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
-        ResolvedJavaMethod subst = replacements.getMethodSubstitutionMethod(method);
-        if (subst != null) {
-            if (b.parsingReplacement() || InlineDuringParsing.getValue()) {
-                // Forced inlining of intrinsics
-                return new InlineInfo(subst, true, true);
-            }
-        }
-        if (b.parsingReplacement()) {
-            assert nodeIntrinsification.getIntrinsic(method) == null && method.getAnnotation(Word.Operation.class) == null && method.getAnnotation(HotSpotOperation.class) == null &&
-                            !nodeIntrinsification.isFoldable(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
-
-            // Force inlining when parsing replacements
-            return new InlineInfo(method, true, true);
-        } else {
-            assert nodeIntrinsification.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
-                            method.format("%h.%n"), b);
-            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
-                return new InlineInfo(method, false, false);
-            }
-        }
-        return null;
-    }
-
-    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
-        if (b.parsingReplacement()) {
-            boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null;
-            Replacement replacement = b.getReplacement();
-            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"),
-                            method.format("%h.%n(%p)"));
-        }
-    }
-}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Mon Mar 23 16:11:48 2015 +0100
@@ -23,8 +23,13 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.phases.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.replacements.StandardGraphBuilderPlugins.BoxPlugin;
 
 /**
@@ -65,6 +70,22 @@
                 return;
             }
         }
+
         super.register(plugin, declaringClass, name, argumentTypes);
     }
+
+    @Override
+    public void checkNewNodes(GraphBuilderContext b, InvocationPlugin plugin, NodeIterable<Node> newNodes) {
+        if (GraalOptions.ImmutableCode.getValue()) {
+            for (Node node : newNodes) {
+                if (node instanceof ConstantNode) {
+                    ConstantNode c = (ConstantNode) node;
+                    if (c.getKind() == Kind.Object && !AheadOfTimeVerificationPhase.isLegalObjectConstant(c)) {
+                        throw new AssertionError("illegal constant node in AOT: " + node);
+                    }
+                }
+            }
+        }
+        super.checkNewNodes(b, plugin, newNodes);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethodImpl.java	Mon Mar 23 16:11:48 2015 +0100
@@ -526,7 +526,7 @@
             Method result = holder.mirror().getDeclaredMethod(name, signatureToTypes());
             toJavaCache = result;
             return result;
-        } catch (NoSuchMethodException e) {
+        } catch (NoSuchMethodException | NoClassDefFoundError e) {
             return null;
         }
     }
@@ -539,7 +539,7 @@
             Constructor<?> result = holder.mirror().getDeclaredConstructor(signatureToTypes());
             toJavaCache = result;
             return result;
-        } catch (NoSuchMethodException e) {
+        } catch (NoSuchMethodException | NoClassDefFoundError e) {
             return null;
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Mon Mar 23 16:11:48 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 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.hotspot.meta.*;
@@ -53,7 +54,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
+        if (javaClass.isConstant() && !GraalOptions.ImmutableCode.getValue()) {
             HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
             JavaConstant classLoader = c.getClassLoader();
             if (classLoader != null) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java	Mon Mar 23 16:11:48 2015 +0100
@@ -32,9 +32,8 @@
 import com.oracle.graal.phases.tiers.*;
 
 /**
- * Checks for illegal object constants in a graph processed for AOT compilation. The only legal
- * object constants are {@linkplain String#intern() interned} strings as they will be installed in
- * the Class Data Sharing (CDS) space.
+ * Checks for {@link #isLegalObjectConstant(ConstantNode) illegal} object constants in a graph
+ * processed for AOT compilation.
  *
  * @see LoadJavaMirrorWithKlassPhase
  */
@@ -43,13 +42,17 @@
     @Override
     protected boolean verify(StructuredGraph graph, PhaseContext context) {
         for (ConstantNode node : getConstantNodes(graph)) {
-            if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) {
+            if (isLegalObjectConstant(node)) {
                 throw new VerificationError("illegal object constant: " + node);
             }
         }
         return true;
     }
 
+    public static boolean isLegalObjectConstant(ConstantNode node) {
+        return isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node);
+    }
+
     private static boolean isObject(ConstantNode node) {
         return node.getKind() == Kind.Object;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Mon Mar 23 16:11:48 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import static com.oracle.graal.nodes.spi.Replacements.*;
-
 import java.lang.reflect.*;
 import java.util.zip.*;
 
@@ -64,9 +62,7 @@
         replacements.registerSubstitutions(CRC32.class, CRC32Substitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
-        if (SELF_RECURSIVE_INTRINSICS_ENABLED) {
-            replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.AESCrypt"), AESCryptSubstitutions.class);
-            replacements.registerSubstitutions(new NamedType("com.sun.crypto.provider.CipherBlockChaining"), CipherBlockChainingSubstitutions.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/stubs/ForeignCallStub.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Mon Mar 23 16:11:48 2015 +0100
@@ -192,7 +192,7 @@
         StructuredGraph graph = new StructuredGraph(toString(), null, AllowAssumptions.NO);
         graph.disableInlinedMethodRecording();
 
-        GraphKit kit = new GraphKit(graph, providers, wordTypes);
+        GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins());
         ParameterNode[] params = createParameters(kit, args);
 
         ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Mon Mar 23 16:11:48 2015 +0100
@@ -29,9 +29,10 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
+import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
@@ -94,7 +95,8 @@
 
         assert SnippetGraphUnderConstruction.get() == null;
         SnippetGraphUnderConstruction.set(graph);
-        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, method).apply(graph);
+        ReplacementContext initialReplacementContext = new ReplacementContext(method, method);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(graph);
         SnippetGraphUnderConstruction.set(null);
 
         graph.setGuardsStage(GuardsStage.FLOATING_GUARDS);
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Mon Mar 23 16:11:48 2015 +0100
@@ -27,6 +27,7 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
 import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+import static com.oracle.graal.java.HIRFrameStateBuilder.*;
 
 import java.util.*;
 
@@ -38,10 +39,12 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.Replacement;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.GraphBuilderPhase.Instance.BytecodeParser;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.options.*;
 import com.oracle.graal.phases.*;
 
@@ -81,7 +84,7 @@
      * happen when a call to a {@link MethodSubstitution} is encountered or the root of compilation
      * is a {@link MethodSubstitution} or a snippet.
      */
-    static class ReplacementContext implements Replacement {
+    public static class ReplacementContext implements Replacement {
         /**
          * The method being replaced.
          */
@@ -120,6 +123,11 @@
         IntrinsicContext asIntrinsic() {
             return null;
         }
+
+        @Override
+        public String toString() {
+            return "Replacement{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + "}";
+        }
     }
 
     /**
@@ -128,25 +136,37 @@
      * information required to build a frame state denoting the JVM state just before the
      * intrinsified call.
      */
-    static class IntrinsicContext extends ReplacementContext {
+    public static class IntrinsicContext extends ReplacementContext {
 
         /**
-         * The arguments to the intrinsified invocation.
+         * BCI denoting an intrinsic is being parsed for inlining after the caller has been parsed.
          */
-        private final ValueNode[] invokeArgs;
+        public static final int POST_PARSE_INLINE_BCI = -1;
+
+        /**
+         * BCI denoting an intrinsic is the compilation root.
+         */
+        public static final int ROOT_COMPILATION_BCI = -2;
 
         /**
-         * The BCI of the intrinsified invocation.
+         * The arguments to the intrinsic.
          */
-        private final int invokeBci;
+        ValueNode[] args;
 
-        private FrameState invokeStateBefore;
-        private FrameState invokeStateDuring;
+        /**
+         * The BCI of the intrinsified invocation, {@link #POST_PARSE_INLINE_BCI} or
+         * {@link #ROOT_COMPILATION_BCI}.
+         */
+        final int bci;
 
-        public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] invokeArgs, int invokeBci) {
+        private FrameState stateBeforeCache;
+
+        public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod substitute, ValueNode[] args, int bci) {
             super(method, substitute);
-            this.invokeArgs = invokeArgs;
-            this.invokeBci = invokeBci;
+            assert bci != POST_PARSE_INLINE_BCI || args == null;
+            this.args = args;
+            this.bci = bci;
+            assert !isCompilationRoot() || method.hasBytecodes() : "Cannot intrinsic for native or abstract method " + method.format("%H.%n(%p)");
         }
 
         @Override
@@ -154,34 +174,56 @@
             return true;
         }
 
-        /**
-         * Gets the frame state that will restart the interpreter just before the intrinsified
-         * invocation.
-         */
-        public FrameState getInvokeStateBefore(BytecodeParser parent) {
-            assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext;
-            if (invokeStateDuring == null) {
-                assert invokeStateBefore == null;
-                // Find the ancestor calling the replaced method
-                BytecodeParser ancestor = parent;
-                while (ancestor.parsingReplacement()) {
-                    ancestor = ancestor.getParent();
-                }
-                invokeStateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true);
-                invokeStateBefore = invokeStateDuring.duplicateModifiedBeforeCall(invokeBci, Kind.Void, invokeArgs);
-            }
-            return invokeStateBefore;
+        public boolean isPostParseInlined() {
+            return bci == POST_PARSE_INLINE_BCI;
+        }
+
+        public boolean isCompilationRoot() {
+            return bci == ROOT_COMPILATION_BCI;
         }
 
-        public FrameState getInvokeStateDuring() {
-            assert invokeStateDuring != null : "must only be called after getInvokeStateBefore()";
-            return invokeStateDuring;
+        public FrameState getInvokeStateBefore(StructuredGraph graph, BytecodeParser parent) {
+            if (isCompilationRoot()) {
+                int maxLocals = method.getMaxLocals();
+                // The 'args' were initialized based on the intrinsic method but a
+                // frame state's 'locals' needs to have the same length as the frame
+                // state method's 'max_locals'.
+                ValueNode[] locals = maxLocals == args.length ? args : Arrays.copyOf(args, maxLocals);
+                ValueNode[] stack = EMPTY_ARRAY;
+                int stackSize = 0;
+                ValueNode[] locks = EMPTY_ARRAY;
+                List<MonitorIdNode> monitorIds = Collections.emptyList();
+                return graph.add(new FrameState(null, method, 0, locals, stack, stackSize, locks, monitorIds, false, false));
+            } else if (isPostParseInlined()) {
+                return graph.add(new FrameState(BytecodeFrame.BEFORE_BCI));
+            } else {
+                assert !parent.parsingReplacement() || parent.replacementContext instanceof IntrinsicContext;
+                if (stateBeforeCache == null) {
+                    assert stateBeforeCache == null;
+
+                    // Find the non-intrinsic ancestor calling the intrinsified method
+                    BytecodeParser ancestor = parent;
+                    while (ancestor.parsingReplacement()) {
+                        assert ancestor.replacementContext instanceof IntrinsicContext;
+                        ancestor = ancestor.getParent();
+                    }
+                    FrameState stateDuring = ancestor.getFrameState().create(ancestor.bci(), ancestor.getParent(), true);
+                    stateBeforeCache = stateDuring.duplicateModifiedBeforeCall(bci, Kind.Void, args);
+                }
+                return stateBeforeCache;
+            }
         }
 
         @Override
         IntrinsicContext asIntrinsic() {
             return this;
         }
+
+        @Override
+        public String toString() {
+            return "Intrinsic{original: " + method.format("%H.%n(%p)") + ", replacement: " + replacement.format("%H.%n(%p)") + ", bci: " + bci +
+                            (args == null ? "" : ", args: " + Arrays.toString(args)) + (stateBeforeCache == null ? "" : ", stateBefore: " + stateBeforeCache) + "}";
+        }
     }
 
     /**
@@ -333,11 +375,8 @@
     protected abstract ValueNode genLoadIndexed(ValueNode index, ValueNode array, Kind kind);
 
     private void genLoadIndexed(Kind kind) {
-
-        emitExplicitExceptions(frameState.peek(1), frameState.peek(0));
-
         ValueNode index = frameState.ipop();
-        ValueNode array = frameState.apop();
+        ValueNode array = emitExplicitExceptions(frameState.apop(), index);
         if (!tryLoadIndexedPlugin(kind, index, array)) {
             frameState.push(kind.getStackKind(), append(genLoadIndexed(array, index, kind)));
         }
@@ -360,11 +399,9 @@
     protected abstract void genStoreIndexed(ValueNode array, ValueNode index, Kind kind, ValueNode value);
 
     private void genStoreIndexed(Kind kind) {
-        emitExplicitExceptions(frameState.peek(2), frameState.peek(1));
-
         ValueNode value = frameState.pop(kind.getStackKind());
         ValueNode index = frameState.ipop();
-        ValueNode array = frameState.apop();
+        ValueNode array = emitExplicitExceptions(frameState.apop(), index);
         genStoreIndexed(array, index, kind, value);
     }
 
@@ -832,10 +869,8 @@
     protected abstract ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field);
 
     private void genGetField(JavaField field) {
-        emitExplicitExceptions(frameState.peek(0), null);
-
         Kind kind = field.getKind();
-        ValueNode receiver = frameState.apop();
+        ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
         if ((field instanceof ResolvedJavaField) && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
             LoadFieldPlugin loadFieldPlugin = this.graphBuilderConfig.getPlugins().getLoadFieldPlugin();
             if (loadFieldPlugin == null || !loadFieldPlugin.apply((GraphBuilderContext) this, receiver, (ResolvedJavaField) field)) {
@@ -846,36 +881,53 @@
         }
     }
 
-    protected abstract void emitNullCheck(ValueNode receiver);
+    /**
+     * Emits control flow to null check a receiver if it's stamp does not indicate it is
+     * {@linkplain StampTool#isPointerNonNull always non-null}.
+     *
+     * @return the receiver with a stamp indicating non-nullness
+     */
+    protected abstract ValueNode emitExplicitNullCheck(ValueNode receiver);
 
-    protected abstract void emitBoundsCheck(ValueNode index, ValueNode length);
+    /**
+     * Emits control flow to check an array index is within bounds of an array's length.
+     *
+     * @param index the index to check
+     * @param length the length of the array being indexed
+     */
+    protected abstract void emitExplicitBoundsCheck(ValueNode index, ValueNode length);
 
     private static final DebugMetric EXPLICIT_EXCEPTIONS = Debug.metric("ExplicitExceptions");
 
     protected abstract ValueNode genArrayLength(ValueNode x);
 
-    protected void emitExplicitExceptions(ValueNode receiver, ValueNode outOfBoundsIndex) {
+    /**
+     * @param receiver the receiver of an object based operation
+     * @param index the index of an array based operation that is to be tested for out of bounds.
+     *            This is null for a non-array operation.
+     * @return the receiver value possibly modified to have a tighter stamp
+     */
+    protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
         assert receiver != null;
         if (graphBuilderConfig.omitAllExceptionEdges() || profilingInfo == null ||
                         (optimisticOpts.useExceptionProbabilityForOperations() && profilingInfo.getExceptionSeen(bci()) == TriState.FALSE && !GraalOptions.StressExplicitExceptionCode.getValue())) {
-            return;
+            return receiver;
         }
 
-        emitNullCheck(receiver);
-        if (outOfBoundsIndex != null) {
-            ValueNode length = append(genArrayLength(receiver));
-            emitBoundsCheck(outOfBoundsIndex, length);
+        ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
+        if (index != null) {
+            ValueNode length = append(genArrayLength(nonNullReceiver));
+            emitExplicitBoundsCheck(index, length);
         }
         EXPLICIT_EXCEPTIONS.increment();
+        return nonNullReceiver;
     }
 
     protected abstract void genStoreField(ValueNode receiver, ResolvedJavaField field, ValueNode value);
 
     private void genPutField(JavaField field) {
-        emitExplicitExceptions(frameState.peek(1), null);
-
         ValueNode value = frameState.pop(field.getKind().getStackKind());
-        ValueNode receiver = frameState.apop();
+        ValueNode receiver = emitExplicitExceptions(frameState.apop(), null);
         if (field instanceof ResolvedJavaField && ((ResolvedJavaField) field).getDeclaringClass().isInitialized()) {
             genStoreField(receiver, (ResolvedJavaField) field, value);
         } else {
@@ -1033,7 +1085,7 @@
 
     protected abstract ValueNode appendConstant(JavaConstant constant);
 
-    protected abstract ValueNode append(ValueNode v);
+    protected abstract <T extends ValueNode> T append(T v);
 
     protected boolean isNeverExecutedCode(double probability) {
         return probability == 0 && optimisticOpts.removeNeverExecutedCode();
@@ -1093,214 +1145,214 @@
 
         // Checkstyle: stop
         // @formatter:off
-    switch (opcode) {
-        case NOP            : /* nothing to do */ break;
-        case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
-        case ICONST_M1      : // fall through
-        case ICONST_0       : // fall through
-        case ICONST_1       : // fall through
-        case ICONST_2       : // fall through
-        case ICONST_3       : // fall through
-        case ICONST_4       : // fall through
-        case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
-        case LCONST_0       : // fall through
-        case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
-        case FCONST_0       : // fall through
-        case FCONST_1       : // fall through
-        case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
-        case DCONST_0       : // fall through
-        case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
-        case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
-        case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
-        case LDC            : // fall through
-        case LDC_W          : // fall through
-        case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
-        case ILOAD          : loadLocal(stream.readLocalIndex(), Kind.Int); break;
-        case LLOAD          : loadLocal(stream.readLocalIndex(), Kind.Long); break;
-        case FLOAD          : loadLocal(stream.readLocalIndex(), Kind.Float); break;
-        case DLOAD          : loadLocal(stream.readLocalIndex(), Kind.Double); break;
-        case ALOAD          : loadLocal(stream.readLocalIndex(), Kind.Object); break;
-        case ILOAD_0        : // fall through
-        case ILOAD_1        : // fall through
-        case ILOAD_2        : // fall through
-        case ILOAD_3        : loadLocal(opcode - ILOAD_0, Kind.Int); break;
-        case LLOAD_0        : // fall through
-        case LLOAD_1        : // fall through
-        case LLOAD_2        : // fall through
-        case LLOAD_3        : loadLocal(opcode - LLOAD_0, Kind.Long); break;
-        case FLOAD_0        : // fall through
-        case FLOAD_1        : // fall through
-        case FLOAD_2        : // fall through
-        case FLOAD_3        : loadLocal(opcode - FLOAD_0, Kind.Float); break;
-        case DLOAD_0        : // fall through
-        case DLOAD_1        : // fall through
-        case DLOAD_2        : // fall through
-        case DLOAD_3        : loadLocal(opcode - DLOAD_0, Kind.Double); break;
-        case ALOAD_0        : // fall through
-        case ALOAD_1        : // fall through
-        case ALOAD_2        : // fall through
-        case ALOAD_3        : loadLocal(opcode - ALOAD_0, Kind.Object); break;
-        case IALOAD         : genLoadIndexed(Kind.Int   ); break;
-        case LALOAD         : genLoadIndexed(Kind.Long  ); break;
-        case FALOAD         : genLoadIndexed(Kind.Float ); break;
-        case DALOAD         : genLoadIndexed(Kind.Double); break;
-        case AALOAD         : genLoadIndexed(Kind.Object); break;
-        case BALOAD         : genLoadIndexed(Kind.Byte  ); break;
-        case CALOAD         : genLoadIndexed(Kind.Char  ); break;
-        case SALOAD         : genLoadIndexed(Kind.Short ); break;
-        case ISTORE         : storeLocal(Kind.Int, stream.readLocalIndex()); break;
-        case LSTORE         : storeLocal(Kind.Long, stream.readLocalIndex()); break;
-        case FSTORE         : storeLocal(Kind.Float, stream.readLocalIndex()); break;
-        case DSTORE         : storeLocal(Kind.Double, stream.readLocalIndex()); break;
-        case ASTORE         : storeLocal(Kind.Object, stream.readLocalIndex()); break;
-        case ISTORE_0       : // fall through
-        case ISTORE_1       : // fall through
-        case ISTORE_2       : // fall through
-        case ISTORE_3       : storeLocal(Kind.Int, opcode - ISTORE_0); break;
-        case LSTORE_0       : // fall through
-        case LSTORE_1       : // fall through
-        case LSTORE_2       : // fall through
-        case LSTORE_3       : storeLocal(Kind.Long, opcode - LSTORE_0); break;
-        case FSTORE_0       : // fall through
-        case FSTORE_1       : // fall through
-        case FSTORE_2       : // fall through
-        case FSTORE_3       : storeLocal(Kind.Float, opcode - FSTORE_0); break;
-        case DSTORE_0       : // fall through
-        case DSTORE_1       : // fall through
-        case DSTORE_2       : // fall through
-        case DSTORE_3       : storeLocal(Kind.Double, opcode - DSTORE_0); break;
-        case ASTORE_0       : // fall through
-        case ASTORE_1       : // fall through
-        case ASTORE_2       : // fall through
-        case ASTORE_3       : storeLocal(Kind.Object, opcode - ASTORE_0); break;
-        case IASTORE        : genStoreIndexed(Kind.Int   ); break;
-        case LASTORE        : genStoreIndexed(Kind.Long  ); break;
-        case FASTORE        : genStoreIndexed(Kind.Float ); break;
-        case DASTORE        : genStoreIndexed(Kind.Double); break;
-        case AASTORE        : genStoreIndexed(Kind.Object); break;
-        case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
-        case CASTORE        : genStoreIndexed(Kind.Char  ); break;
-        case SASTORE        : genStoreIndexed(Kind.Short ); break;
-        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
-        case DUP2_X1        : // fall through
-        case DUP2_X2        : // fall through
-        case SWAP           : stackOp(opcode); break;
-        case IADD           : // fall through
-        case ISUB           : // fall through
-        case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
-        case IDIV           : // fall through
-        case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
-        case LADD           : // fall through
-        case LSUB           : // fall through
-        case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
-        case LDIV           : // fall through
-        case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
-        case FADD           : // fall through
-        case FSUB           : // fall through
-        case FMUL           : // fall through
-        case FDIV           : // fall through
-        case FREM           : genArithmeticOp(Kind.Float, opcode); break;
-        case DADD           : // fall through
-        case DSUB           : // fall through
-        case DMUL           : // fall through
-        case DDIV           : // fall through
-        case DREM           : genArithmeticOp(Kind.Double, opcode); break;
-        case INEG           : genNegateOp(Kind.Int); break;
-        case LNEG           : genNegateOp(Kind.Long); break;
-        case FNEG           : genNegateOp(Kind.Float); break;
-        case DNEG           : genNegateOp(Kind.Double); break;
-        case ISHL           : // fall through
-        case ISHR           : // fall through
-        case IUSHR          : genShiftOp(Kind.Int, opcode); break;
-        case IAND           : // fall through
-        case IOR            : // fall through
-        case IXOR           : genLogicOp(Kind.Int, opcode); break;
-        case LSHL           : // fall through
-        case LSHR           : // fall through
-        case LUSHR          : genShiftOp(Kind.Long, opcode); break;
-        case LAND           : // fall through
-        case LOR            : // fall through
-        case LXOR           : genLogicOp(Kind.Long, opcode); break;
-        case IINC           : genIncrement(); break;
-        case I2F            : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break;
-        case I2D            : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break;
-        case L2F            : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break;
-        case L2D            : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break;
-        case F2I            : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break;
-        case F2L            : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break;
-        case F2D            : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break;
-        case D2I            : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break;
-        case D2L            : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break;
-        case D2F            : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break;
-        case L2I            : genNarrow(Kind.Long, Kind.Int); break;
-        case I2L            : genSignExtend(Kind.Int, Kind.Long); break;
-        case I2B            : genSignExtend(Kind.Byte, Kind.Int); break;
-        case I2S            : genSignExtend(Kind.Short, Kind.Int); break;
-        case I2C            : genZeroExtend(Kind.Char, Kind.Int); break;
-        case LCMP           : genCompareOp(Kind.Long, false); break;
-        case FCMPL          : genCompareOp(Kind.Float, true); break;
-        case FCMPG          : genCompareOp(Kind.Float, false); break;
-        case DCMPL          : genCompareOp(Kind.Double, true); break;
-        case DCMPG          : genCompareOp(Kind.Double, false); break;
-        case IFEQ           : genIfZero(Condition.EQ); break;
-        case IFNE           : genIfZero(Condition.NE); break;
-        case IFLT           : genIfZero(Condition.LT); break;
-        case IFGE           : genIfZero(Condition.GE); break;
-        case IFGT           : genIfZero(Condition.GT); break;
-        case IFLE           : genIfZero(Condition.LE); break;
-        case IF_ICMPEQ      : genIfSame(Kind.Int, Condition.EQ); break;
-        case IF_ICMPNE      : genIfSame(Kind.Int, Condition.NE); break;
-        case IF_ICMPLT      : genIfSame(Kind.Int, Condition.LT); break;
-        case IF_ICMPGE      : genIfSame(Kind.Int, Condition.GE); break;
-        case IF_ICMPGT      : genIfSame(Kind.Int, Condition.GT); break;
-        case IF_ICMPLE      : genIfSame(Kind.Int, Condition.LE); break;
-        case IF_ACMPEQ      : genIfSame(Kind.Object, Condition.EQ); break;
-        case IF_ACMPNE      : genIfSame(Kind.Object, Condition.NE); break;
-        case GOTO           : genGoto(); break;
-        case JSR            : genJsr(stream.readBranchDest()); break;
-        case RET            : genRet(stream.readLocalIndex()); break;
-        case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
-        case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
-        case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
-        case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
-        case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
-        case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
-        case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
-        case RETURN         : genReturn(null, Kind.Void); break;
-        case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
-        case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
-        case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
-        case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
-        case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
-        case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
-        case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
-        case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
-        case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
-        case NEW            : genNewInstance(stream.readCPI()); break;
-        case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
-        case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
-        case ARRAYLENGTH    : genArrayLength(); break;
-        case ATHROW         : genThrow(); break;
-        case CHECKCAST      : genCheckCast(); break;
-        case INSTANCEOF     : genInstanceOf(); break;
-        case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
-        case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
-        case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
-        case IFNULL         : genIfNull(Condition.EQ); break;
-        case IFNONNULL      : genIfNull(Condition.NE); break;
-        case GOTO_W         : genGoto(); break;
-        case JSR_W          : genJsr(stream.readBranchDest()); break;
-        case BREAKPOINT:
-            throw new BailoutException("concurrent setting of breakpoint");
-        default:
-            throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
-    }
-    // @formatter:on
+        switch (opcode) {
+            case NOP            : /* nothing to do */ break;
+            case ACONST_NULL    : frameState.apush(appendConstant(JavaConstant.NULL_POINTER)); break;
+            case ICONST_M1      : // fall through
+            case ICONST_0       : // fall through
+            case ICONST_1       : // fall through
+            case ICONST_2       : // fall through
+            case ICONST_3       : // fall through
+            case ICONST_4       : // fall through
+            case ICONST_5       : frameState.ipush(appendConstant(JavaConstant.forInt(opcode - ICONST_0))); break;
+            case LCONST_0       : // fall through
+            case LCONST_1       : frameState.lpush(appendConstant(JavaConstant.forLong(opcode - LCONST_0))); break;
+            case FCONST_0       : // fall through
+            case FCONST_1       : // fall through
+            case FCONST_2       : frameState.fpush(appendConstant(JavaConstant.forFloat(opcode - FCONST_0))); break;
+            case DCONST_0       : // fall through
+            case DCONST_1       : frameState.dpush(appendConstant(JavaConstant.forDouble(opcode - DCONST_0))); break;
+            case BIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readByte()))); break;
+            case SIPUSH         : frameState.ipush(appendConstant(JavaConstant.forInt(stream.readShort()))); break;
+            case LDC            : // fall through
+            case LDC_W          : // fall through
+            case LDC2_W         : genLoadConstant(stream.readCPI(), opcode); break;
+            case ILOAD          : loadLocal(stream.readLocalIndex(), Kind.Int); break;
+            case LLOAD          : loadLocal(stream.readLocalIndex(), Kind.Long); break;
+            case FLOAD          : loadLocal(stream.readLocalIndex(), Kind.Float); break;
+            case DLOAD          : loadLocal(stream.readLocalIndex(), Kind.Double); break;
+            case ALOAD          : loadLocal(stream.readLocalIndex(), Kind.Object); break;
+            case ILOAD_0        : // fall through
+            case ILOAD_1        : // fall through
+            case ILOAD_2        : // fall through
+            case ILOAD_3        : loadLocal(opcode - ILOAD_0, Kind.Int); break;
+            case LLOAD_0        : // fall through
+            case LLOAD_1        : // fall through
+            case LLOAD_2        : // fall through
+            case LLOAD_3        : loadLocal(opcode - LLOAD_0, Kind.Long); break;
+            case FLOAD_0        : // fall through
+            case FLOAD_1        : // fall through
+            case FLOAD_2        : // fall through
+            case FLOAD_3        : loadLocal(opcode - FLOAD_0, Kind.Float); break;
+            case DLOAD_0        : // fall through
+            case DLOAD_1        : // fall through
+            case DLOAD_2        : // fall through
+            case DLOAD_3        : loadLocal(opcode - DLOAD_0, Kind.Double); break;
+            case ALOAD_0        : // fall through
+            case ALOAD_1        : // fall through
+            case ALOAD_2        : // fall through
+            case ALOAD_3        : loadLocal(opcode - ALOAD_0, Kind.Object); break;
+            case IALOAD         : genLoadIndexed(Kind.Int   ); break;
+            case LALOAD         : genLoadIndexed(Kind.Long  ); break;
+            case FALOAD         : genLoadIndexed(Kind.Float ); break;
+            case DALOAD         : genLoadIndexed(Kind.Double); break;
+            case AALOAD         : genLoadIndexed(Kind.Object); break;
+            case BALOAD         : genLoadIndexed(Kind.Byte  ); break;
+            case CALOAD         : genLoadIndexed(Kind.Char  ); break;
+            case SALOAD         : genLoadIndexed(Kind.Short ); break;
+            case ISTORE         : storeLocal(Kind.Int, stream.readLocalIndex()); break;
+            case LSTORE         : storeLocal(Kind.Long, stream.readLocalIndex()); break;
+            case FSTORE         : storeLocal(Kind.Float, stream.readLocalIndex()); break;
+            case DSTORE         : storeLocal(Kind.Double, stream.readLocalIndex()); break;
+            case ASTORE         : storeLocal(Kind.Object, stream.readLocalIndex()); break;
+            case ISTORE_0       : // fall through
+            case ISTORE_1       : // fall through
+            case ISTORE_2       : // fall through
+            case ISTORE_3       : storeLocal(Kind.Int, opcode - ISTORE_0); break;
+            case LSTORE_0       : // fall through
+            case LSTORE_1       : // fall through
+            case LSTORE_2       : // fall through
+            case LSTORE_3       : storeLocal(Kind.Long, opcode - LSTORE_0); break;
+            case FSTORE_0       : // fall through
+            case FSTORE_1       : // fall through
+            case FSTORE_2       : // fall through
+            case FSTORE_3       : storeLocal(Kind.Float, opcode - FSTORE_0); break;
+            case DSTORE_0       : // fall through
+            case DSTORE_1       : // fall through
+            case DSTORE_2       : // fall through
+            case DSTORE_3       : storeLocal(Kind.Double, opcode - DSTORE_0); break;
+            case ASTORE_0       : // fall through
+            case ASTORE_1       : // fall through
+            case ASTORE_2       : // fall through
+            case ASTORE_3       : storeLocal(Kind.Object, opcode - ASTORE_0); break;
+            case IASTORE        : genStoreIndexed(Kind.Int   ); break;
+            case LASTORE        : genStoreIndexed(Kind.Long  ); break;
+            case FASTORE        : genStoreIndexed(Kind.Float ); break;
+            case DASTORE        : genStoreIndexed(Kind.Double); break;
+            case AASTORE        : genStoreIndexed(Kind.Object); break;
+            case BASTORE        : genStoreIndexed(Kind.Byte  ); break;
+            case CASTORE        : genStoreIndexed(Kind.Char  ); break;
+            case SASTORE        : genStoreIndexed(Kind.Short ); break;
+            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
+            case DUP2_X1        : // fall through
+            case DUP2_X2        : // fall through
+            case SWAP           : stackOp(opcode); break;
+            case IADD           : // fall through
+            case ISUB           : // fall through
+            case IMUL           : genArithmeticOp(Kind.Int, opcode); break;
+            case IDIV           : // fall through
+            case IREM           : genIntegerDivOp(Kind.Int, opcode); break;
+            case LADD           : // fall through
+            case LSUB           : // fall through
+            case LMUL           : genArithmeticOp(Kind.Long, opcode); break;
+            case LDIV           : // fall through
+            case LREM           : genIntegerDivOp(Kind.Long, opcode); break;
+            case FADD           : // fall through
+            case FSUB           : // fall through
+            case FMUL           : // fall through
+            case FDIV           : // fall through
+            case FREM           : genArithmeticOp(Kind.Float, opcode); break;
+            case DADD           : // fall through
+            case DSUB           : // fall through
+            case DMUL           : // fall through
+            case DDIV           : // fall through
+            case DREM           : genArithmeticOp(Kind.Double, opcode); break;
+            case INEG           : genNegateOp(Kind.Int); break;
+            case LNEG           : genNegateOp(Kind.Long); break;
+            case FNEG           : genNegateOp(Kind.Float); break;
+            case DNEG           : genNegateOp(Kind.Double); break;
+            case ISHL           : // fall through
+            case ISHR           : // fall through
+            case IUSHR          : genShiftOp(Kind.Int, opcode); break;
+            case IAND           : // fall through
+            case IOR            : // fall through
+            case IXOR           : genLogicOp(Kind.Int, opcode); break;
+            case LSHL           : // fall through
+            case LSHR           : // fall through
+            case LUSHR          : genShiftOp(Kind.Long, opcode); break;
+            case LAND           : // fall through
+            case LOR            : // fall through
+            case LXOR           : genLogicOp(Kind.Long, opcode); break;
+            case IINC           : genIncrement(); break;
+            case I2F            : genFloatConvert(FloatConvert.I2F, Kind.Int, Kind.Float); break;
+            case I2D            : genFloatConvert(FloatConvert.I2D, Kind.Int, Kind.Double); break;
+            case L2F            : genFloatConvert(FloatConvert.L2F, Kind.Long, Kind.Float); break;
+            case L2D            : genFloatConvert(FloatConvert.L2D, Kind.Long, Kind.Double); break;
+            case F2I            : genFloatConvert(FloatConvert.F2I, Kind.Float, Kind.Int); break;
+            case F2L            : genFloatConvert(FloatConvert.F2L, Kind.Float, Kind.Long); break;
+            case F2D            : genFloatConvert(FloatConvert.F2D, Kind.Float, Kind.Double); break;
+            case D2I            : genFloatConvert(FloatConvert.D2I, Kind.Double, Kind.Int); break;
+            case D2L            : genFloatConvert(FloatConvert.D2L, Kind.Double, Kind.Long); break;
+            case D2F            : genFloatConvert(FloatConvert.D2F, Kind.Double, Kind.Float); break;
+            case L2I            : genNarrow(Kind.Long, Kind.Int); break;
+            case I2L            : genSignExtend(Kind.Int, Kind.Long); break;
+            case I2B            : genSignExtend(Kind.Byte, Kind.Int); break;
+            case I2S            : genSignExtend(Kind.Short, Kind.Int); break;
+            case I2C            : genZeroExtend(Kind.Char, Kind.Int); break;
+            case LCMP           : genCompareOp(Kind.Long, false); break;
+            case FCMPL          : genCompareOp(Kind.Float, true); break;
+            case FCMPG          : genCompareOp(Kind.Float, false); break;
+            case DCMPL          : genCompareOp(Kind.Double, true); break;
+            case DCMPG          : genCompareOp(Kind.Double, false); break;
+            case IFEQ           : genIfZero(Condition.EQ); break;
+            case IFNE           : genIfZero(Condition.NE); break;
+            case IFLT           : genIfZero(Condition.LT); break;
+            case IFGE           : genIfZero(Condition.GE); break;
+            case IFGT           : genIfZero(Condition.GT); break;
+            case IFLE           : genIfZero(Condition.LE); break;
+            case IF_ICMPEQ      : genIfSame(Kind.Int, Condition.EQ); break;
+            case IF_ICMPNE      : genIfSame(Kind.Int, Condition.NE); break;
+            case IF_ICMPLT      : genIfSame(Kind.Int, Condition.LT); break;
+            case IF_ICMPGE      : genIfSame(Kind.Int, Condition.GE); break;
+            case IF_ICMPGT      : genIfSame(Kind.Int, Condition.GT); break;
+            case IF_ICMPLE      : genIfSame(Kind.Int, Condition.LE); break;
+            case IF_ACMPEQ      : genIfSame(Kind.Object, Condition.EQ); break;
+            case IF_ACMPNE      : genIfSame(Kind.Object, Condition.NE); break;
+            case GOTO           : genGoto(); break;
+            case JSR            : genJsr(stream.readBranchDest()); break;
+            case RET            : genRet(stream.readLocalIndex()); break;
+            case TABLESWITCH    : genSwitch(new BytecodeTableSwitch(getStream(), bci())); break;
+            case LOOKUPSWITCH   : genSwitch(new BytecodeLookupSwitch(getStream(), bci())); break;
+            case IRETURN        : genReturn(frameState.ipop(), Kind.Int); break;
+            case LRETURN        : genReturn(frameState.lpop(), Kind.Long); break;
+            case FRETURN        : genReturn(frameState.fpop(), Kind.Float); break;
+            case DRETURN        : genReturn(frameState.dpop(), Kind.Double); break;
+            case ARETURN        : genReturn(frameState.apop(), Kind.Object); break;
+            case RETURN         : genReturn(null, Kind.Void); break;
+            case GETSTATIC      : cpi = stream.readCPI(); genGetStatic(lookupField(cpi, opcode)); break;
+            case PUTSTATIC      : cpi = stream.readCPI(); genPutStatic(lookupField(cpi, opcode)); break;
+            case GETFIELD       : cpi = stream.readCPI(); genGetField(lookupField(cpi, opcode)); break;
+            case PUTFIELD       : cpi = stream.readCPI(); genPutField(lookupField(cpi, opcode)); break;
+            case INVOKEVIRTUAL  : cpi = stream.readCPI(); genInvokeVirtual(lookupMethod(cpi, opcode)); break;
+            case INVOKESPECIAL  : cpi = stream.readCPI(); genInvokeSpecial(lookupMethod(cpi, opcode)); break;
+            case INVOKESTATIC   : cpi = stream.readCPI(); genInvokeStatic(lookupMethod(cpi, opcode)); break;
+            case INVOKEINTERFACE: cpi = stream.readCPI(); genInvokeInterface(lookupMethod(cpi, opcode)); break;
+            case INVOKEDYNAMIC  : cpi = stream.readCPI4(); genInvokeDynamic(lookupMethod(cpi, opcode)); break;
+            case NEW            : genNewInstance(stream.readCPI()); break;
+            case NEWARRAY       : genNewPrimitiveArray(stream.readLocalIndex()); break;
+            case ANEWARRAY      : genNewObjectArray(stream.readCPI()); break;
+            case ARRAYLENGTH    : genArrayLength(); break;
+            case ATHROW         : genThrow(); break;
+            case CHECKCAST      : genCheckCast(); break;
+            case INSTANCEOF     : genInstanceOf(); break;
+            case MONITORENTER   : genMonitorEnter(frameState.apop(), stream.nextBCI()); break;
+            case MONITOREXIT    : genMonitorExit(frameState.apop(), null, stream.nextBCI()); break;
+            case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break;
+            case IFNULL         : genIfNull(Condition.EQ); break;
+            case IFNONNULL      : genIfNull(Condition.NE); break;
+            case GOTO_W         : genGoto(); break;
+            case JSR_W          : genJsr(stream.readBranchDest()); break;
+            case BREAKPOINT:
+                throw new BailoutException("concurrent setting of breakpoint");
+            default:
+                throw new BailoutException("Unsupported opcode %d (%s) [bci=%d]", opcode, nameOf(opcode), bci);
+        }
+        // @formatter:on
         // Checkstyle: resume
     }
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java	Mon Mar 23 16:11:48 2015 +0100
@@ -51,6 +51,15 @@
      * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract)
      */
     public String disassemble(ResolvedJavaMethod method) {
+        return disassemble(method, 0, Integer.MAX_VALUE);
+    }
+
+    /**
+     * Disassembles the bytecode of a given method in a {@code javap}-like format.
+     *
+     * @return {@code null} if {@code method} has no bytecode (e.g., it is native or abstract)
+     */
+    public String disassemble(ResolvedJavaMethod method, int startBci, int endBci) {
         if (method.getCode() == null) {
             return null;
         }
@@ -60,10 +69,11 @@
         int opcode = stream.currentBC();
         while (opcode != Bytecodes.END) {
             int bci = stream.currentBCI();
-            String mnemonic = Bytecodes.nameOf(opcode);
-            buf.append(String.format("%4d: %-14s", bci, mnemonic));
-            if (stream.nextBCI() > bci + 1) {
-                // @formatter:off
+            if (bci >= startBci && bci <= endBci) {
+                String mnemonic = Bytecodes.nameOf(opcode);
+                buf.append(String.format("%4d: %-14s", bci, mnemonic));
+                if (stream.nextBCI() > bci + 1) {
+                    // @formatter:off
                 switch (opcode) {
                     case BIPUSH         : buf.append(stream.readByte()); break;
                     case SIPUSH         : buf.append(stream.readShort()); break;
@@ -211,8 +221,9 @@
                     }
                 }
                 // @formatter:on
+                }
+                buf.append(String.format("%n"));
             }
-            buf.append(String.format("%n"));
             stream.next();
             opcode = stream.currentBC();
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Mar 23 16:11:48 2015 +0100
@@ -25,10 +25,12 @@
 import static com.oracle.graal.api.meta.DeoptimizationAction.*;
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.bytecode.Bytecodes.*;
+import static com.oracle.graal.compiler.common.GraalInternalError.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
+import static com.oracle.graal.compiler.common.type.StampFactory.*;
 import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
 import static com.oracle.graal.nodes.StructuredGraph.*;
+import static com.oracle.graal.nodes.type.StampTool.*;
 import static java.lang.String.*;
 
 import java.util.*;
@@ -48,6 +50,7 @@
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver;
 import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.BciBlockMapping.BciBlock;
 import com.oracle.graal.java.BciBlockMapping.ExceptionDispatchBlock;
@@ -97,7 +100,9 @@
          * Furthermore, if it is non-null and not equal to {@link #rootMethod} then this is the
          * original method for which a snippet exists (e.g., System.arraycopy()).
          */
-        private final ResolvedJavaMethod rootMethodIsReplacement;
+        // private final ResolvedJavaMethod rootMethodIsReplacement;
+
+        private final ReplacementContext initialReplacementContext;
 
         private final GraphBuilderConfiguration graphBuilderConfig;
         private final OptimisticOptimizations optimisticOpts;
@@ -106,20 +111,21 @@
         private final SnippetReflectionProvider snippetReflectionProvider;
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, SnippetReflectionProvider snippetReflectionProvider, ConstantReflectionProvider constantReflection,
-                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) {
+                        GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) {
             this.graphBuilderConfig = graphBuilderConfig;
             this.optimisticOpts = optimisticOpts;
             this.metaAccess = metaAccess;
             this.stampProvider = stampProvider;
             this.constantReflection = constantReflection;
             this.snippetReflectionProvider = snippetReflectionProvider;
-            this.rootMethodIsReplacement = rootMethodIsReplacement;
+            this.initialReplacementContext = initialReplacementContext;
+
             assert metaAccess != null;
         }
 
         public Instance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
-                        OptimisticOptimizations optimisticOpts, ResolvedJavaMethod rootMethodIsReplacement) {
-            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement);
+                        OptimisticOptimizations optimisticOpts, ReplacementContext initialReplacementContext) {
+            this(metaAccess, stampProvider, null, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext);
         }
 
         @Override
@@ -131,10 +137,10 @@
             this.currentGraph = graph;
             TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(), method);
             try {
-                ReplacementContext replacementContext = rootMethodIsReplacement != null ? new ReplacementContext(rootMethodIsReplacement, rootMethod) : null;
+                ReplacementContext replacementContext = initialReplacementContext;
                 BytecodeParser parser = new BytecodeParser(null, metaAccess, method, graphBuilderConfig, optimisticOpts, entryBCI, replacementContext);
                 HIRFrameStateBuilder frameState = new HIRFrameStateBuilder(parser, method, graph);
-                frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || rootMethodIsReplacement != null, graphBuilderConfig.getPlugins().getParameterPlugin());
+                frameState.initializeForMethodStart(graphBuilderConfig.eagerResolving() || replacementContext != null, graphBuilderConfig.getPlugins().getParameterPlugin());
                 parser.build(graph.start(), frameState);
 
                 parser.connectLoopEndToBegin();
@@ -232,6 +238,42 @@
             }
         }
 
+        static class InvocationPluginReceiver implements Receiver {
+            final BytecodeParser parser;
+            ValueNode[] args;
+            ValueNode value;
+
+            public InvocationPluginReceiver(BytecodeParser parser) {
+                this.parser = parser;
+            }
+
+            @Override
+            public ValueNode get() {
+                assert args != null : "Cannot get the receiver of a static method";
+                if (value == null) {
+                    value = parser.nullCheckedValue(args[0]);
+                    if (value != args[0]) {
+                        args[0] = value;
+                    }
+                }
+                return value;
+            }
+
+            @Override
+            public boolean isConstant() {
+                return args[0].isConstant();
+            }
+
+            InvocationPluginReceiver init(ResolvedJavaMethod targetMethod, ValueNode[] newArgs) {
+                if (!targetMethod.isStatic()) {
+                    this.args = newArgs;
+                    this.value = null;
+                    return this;
+                }
+                return null;
+            }
+        }
+
         public class BytecodeParser extends AbstractBytecodeParser implements GraphBuilderContext {
 
             private BciBlockMapping blockMap;
@@ -257,6 +299,7 @@
             private Stack<ExplodedLoopContext> explodeLoopsContext;
             private int nextPeelIteration = 1;
             private boolean controlFlowSplit;
+            private final InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(this);
 
             private FixedWithNextNode[] firstInstructionArray;
             private HIRFrameStateBuilder[] entryStateArray;
@@ -384,6 +427,28 @@
                 }
             }
 
+            /**
+             * Gets a version of a given value that has a
+             * {@linkplain StampTool#isPointerNonNull(ValueNode) non-null} stamp.
+             */
+            ValueNode nullCheckedValue(ValueNode value) {
+                if (!StampTool.isPointerNonNull(value.stamp())) {
+                    IsNullNode condition = currentGraph.unique(new IsNullNode(value));
+                    ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
+                    Stamp stamp = receiverStamp.join(objectNonNull());
+                    FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, InvalidateReprofile, true));
+                    PiNode nonNullReceiver = currentGraph.unique(new PiNode(value, stamp));
+                    nonNullReceiver.setGuard(fixedGuard);
+                    // TODO: Propogating the non-null into the frame state would
+                    // remove subsequent null-checks on the same value. However,
+                    // it currently causes an assertion failure when merging states.
+                    //
+                    // frameState.replace(value, nonNullReceiver);
+                    return nonNullReceiver;
+                }
+                return value;
+            }
+
             private void detectLoops(FixedNode startInstruction) {
                 NodeBitMap visited = currentGraph.createNodeBitMap();
                 NodeBitMap active = currentGraph.createNodeBitMap();
@@ -946,21 +1011,24 @@
             }
 
             @Override
-            protected void emitNullCheck(ValueNode receiver) {
+            protected ValueNode emitExplicitNullCheck(ValueNode receiver) {
                 if (StampTool.isPointerNonNull(receiver.stamp())) {
-                    return;
+                    return receiver;
                 }
                 BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
                 AbstractBeginNode falseSucc = currentGraph.add(new BeginNode());
+                PiNode nonNullReceiver = currentGraph.unique(new PiNode(receiver, receiver.stamp().join(objectNonNull())));
+                nonNullReceiver.setGuard(falseSucc);
                 append(new IfNode(currentGraph.unique(new IsNullNode(receiver)), exception, falseSucc, 0.01));
                 lastInstr = falseSucc;
 
                 exception.setStateAfter(createFrameState(bci()));
                 exception.setNext(handleException(exception, bci()));
+                return nonNullReceiver;
             }
 
             @Override
-            protected void emitBoundsCheck(ValueNode index, ValueNode length) {
+            protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
                 AbstractBeginNode trueSucc = currentGraph.add(new BeginNode());
                 BytecodeExceptionNode exception = currentGraph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
                 append(new IfNode(currentGraph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99));
@@ -1101,11 +1169,16 @@
                     returnType = returnType.resolve(targetMethod.getDeclaringClass());
                 }
                 if (invokeKind.hasReceiver()) {
-                    emitExplicitExceptions(args[0], null);
+                    args[0] = emitExplicitExceptions(args[0], null);
                     if (invokeKind.isIndirect() && profilingInfo != null && this.optimisticOpts.useTypeCheckHints()) {
                         JavaTypeProfile profile = profilingInfo.getTypeProfile(bci());
                         args[0] = TypeProfileProxyNode.proxify(args[0], profile);
                     }
+
+                    if (args[0].isNullConstant()) {
+                        append(new DeoptimizeNode(InvalidateRecompile, NullCheckException));
+                        return;
+                    }
                 }
 
                 if (tryGenericInvocationPlugin(args, targetMethod)) {
@@ -1149,22 +1222,70 @@
                 }
             }
 
+            /**
+             * Contains all the assertion checking logic around the application of an
+             * {@link InvocationPlugin}. This class is only loaded when assertions are enabled.
+             */
+            class InvocationPluginAssertions {
+                final InvocationPlugin plugin;
+                final ValueNode[] args;
+                final ResolvedJavaMethod targetMethod;
+                final Kind resultType;
+                final int beforeStackSize;
+                final boolean needsNullCheck;
+                final int nodeCount;
+                final Mark mark;
+
+                public InvocationPluginAssertions(InvocationPlugin plugin, ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
+                    guarantee(assertionsEnabled(), "%s should only be loaded and instantiated if assertions are enabled", getClass().getSimpleName());
+                    this.plugin = plugin;
+                    this.targetMethod = targetMethod;
+                    this.args = args;
+                    this.resultType = resultType;
+                    this.beforeStackSize = frameState.stackSize;
+                    this.needsNullCheck = !targetMethod.isStatic() && args[0].getKind() == Kind.Object && !StampTool.isPointerNonNull(args[0].stamp());
+                    this.nodeCount = currentGraph.getNodeCount();
+                    this.mark = currentGraph.getMark();
+                }
+
+                String error(String format, Object... a) {
+                    return String.format(format, a) + String.format("%n\tplugin at %s", plugin.getApplySourceLocation(metaAccess));
+                }
+
+                boolean check(boolean pluginResult) {
+                    if (pluginResult == true) {
+                        assert beforeStackSize + resultType.getSlotCount() == frameState.stackSize : error("plugin manipulated the stack incorrectly");
+                        NodeIterable<Node> newNodes = currentGraph.getNewNodes(mark);
+                        assert !needsNullCheck || isPointerNonNull(args[0].stamp()) : error("plugin needs to null check the receiver of %s: receiver=%s", targetMethod.format("%H.%n(%p)"), args[0]);
+                        for (Node n : newNodes) {
+                            if (n instanceof StateSplit) {
+                                StateSplit stateSplit = (StateSplit) n;
+                                assert stateSplit.stateAfter() != null : error("%s node added by plugin for %s need to have a non-null frame state: %s", StateSplit.class.getSimpleName(),
+                                                targetMethod.format("%H.%n(%p)"), stateSplit);
+                            }
+                        }
+                        try {
+                            graphBuilderConfig.getPlugins().getInvocationPlugins().checkNewNodes(BytecodeParser.this, plugin, newNodes);
+                        } catch (Throwable t) {
+                            throw new AssertionError(error("Error in plugin"), t);
+                        }
+                    } else {
+                        assert nodeCount == currentGraph.getNodeCount() : error("plugin that returns false must not create new nodes");
+                        assert beforeStackSize == frameState.stackSize : error("plugin that returns false must modify the stack");
+                    }
+                    return true;
+                }
+            }
+
             private boolean tryInvocationPlugin(ValueNode[] args, ResolvedJavaMethod targetMethod, Kind resultType) {
                 InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
                 if (plugin != null) {
-                    int beforeStackSize = frameState.stackSize;
-                    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, targetMethod, plugin, args)) {
-                        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]) : format(
-                                        "plugin needs to null check the receiver of %s: receiver=%s%n\tplugin at %s", targetMethod.format("%H.%n(%p)"), args[0],
-                                        plugin.getApplySourceLocation(metaAccess));
+                    InvocationPluginAssertions assertions = assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
+                    if (InvocationPlugin.execute(this, targetMethod, plugin, invocationPluginReceiver.init(targetMethod, args), args)) {
+                        assert assertions.check(true);
                         return true;
                     }
-                    assert nodeCount == currentGraph.getNodeCount() : "plugin that returns false must not create new nodes";
-                    assert beforeStackSize == frameState.stackSize : "plugin that returns false must modify the stack";
+                    assert assertions.check(false);
                 }
                 return false;
             }
@@ -1174,18 +1295,6 @@
                 return plugin != null && plugin.apply(this, targetMethod, args);
             }
 
-            private boolean containsNullCheckOf(NodeIterable<Node> nodes, Node value) {
-                for (Node n : nodes) {
-                    if (n instanceof GuardingPiNode) {
-                        GuardingPiNode pi = (GuardingPiNode) n;
-                        if (pi.condition() instanceof IsNullNode) {
-                            return ((IsNullNode) pi.condition()).getValue() == value;
-                        }
-                    }
-                }
-                return false;
-            }
-
             private boolean tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod, InvokeKind invokeKind, JavaType returnType) {
                 InlineInvokePlugin plugin = graphBuilderConfig.getPlugins().getInlineInvokePlugin();
                 if (plugin == null || !invokeKind.isDirect() || !targetMethod.canBeInlined()) {
@@ -1210,13 +1319,30 @@
                 }
                 ReplacementContext context = this.replacementContext;
                 if (context != null && context.isCallToOriginal(targetMethod)) {
-                    assert context.asIntrinsic() == null : "intrinsic cannot call the method it is intrinsifying";
-                    // Self recursive replacement means the original
-                    // method should be called.
-                    if (context.method.hasBytecodes()) {
-                        parseAndInlineCallee(context.method, args, null);
+                    IntrinsicContext intrinsic = context.asIntrinsic();
+                    if (intrinsic != null) {
+                        if (intrinsic.isCompilationRoot()) {
+                            // A root compiled intrinsic needs to deoptimize
+                            // if the slow path is taken
+                            DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, RuntimeConstraint));
+                            deopt.setStateBefore(intrinsic.getInvokeStateBefore(currentGraph, null));
+                            return true;
+                        } else {
+                            // Otherwise inline the original method. Any frame state created
+                            // during the inlining will exclude frame(s) in the
+                            // intrinsic method (see HIRFrameStateBuilder.create(int bci)).
+                            parseAndInlineCallee(context.method, args, null);
+                            return true;
+                        }
                     } else {
-                        return false;
+                        // Self recursive replacement means the original
+                        // method should be called.
+                        if (context.method.hasBytecodes()) {
+                            parseAndInlineCallee(context.method, args, null);
+                            return true;
+                        } else {
+                            return false;
+                        }
                     }
                 } else {
                     if (context == null && inlineInfo.isReplacement) {
@@ -1275,6 +1401,9 @@
             private void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, ReplacementContext calleeReplacementContext) {
                 BytecodeParser parser = new BytecodeParser(this, metaAccess, targetMethod, graphBuilderConfig, optimisticOpts, INVOCATION_ENTRY_BCI, calleeReplacementContext);
                 HIRFrameStateBuilder startFrameState = new HIRFrameStateBuilder(parser, targetMethod, currentGraph);
+                if (!targetMethod.isStatic()) {
+                    args[0] = nullCheckedValue(args[0]);
+                }
                 startFrameState.initializeFromArgumentsArray(args);
                 parser.build(this.lastInstr, startFrameState);
 
@@ -1444,61 +1573,41 @@
                 return ConstantNode.forConstant(constant, metaAccess, currentGraph);
             }
 
-            @SuppressWarnings("unchecked")
             @Override
-            public ValueNode append(ValueNode v) {
+            public <T extends ValueNode> T append(T v) {
                 if (v.graph() != null) {
-                    // This node was already appended to the graph.
                     return v;
                 }
-                if (v instanceof ControlSinkNode) {
-                    return append((ControlSinkNode) v);
-                }
-                if (v instanceof ControlSplitNode) {
-                    return append((ControlSplitNode) v);
-                }
-                if (v instanceof FixedWithNextNode) {
-                    return append((FixedWithNextNode) v);
+                T added = currentGraph.addOrUnique(v);
+                if (added == v) {
+                    updateLastInstruction(v);
                 }
-                if (v instanceof FloatingNode) {
-                    return append((FloatingNode) v);
-                }
-                throw GraalInternalError.shouldNotReachHere("Can not append Node of type: " + v.getClass().getName());
-            }
-
-            public <T extends ControlSinkNode> T append(T fixed) {
-                assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
-                assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-                T added = currentGraph.add(fixed);
-                lastInstr.setNext(added);
-                lastInstr = null;
                 return added;
             }
 
-            public <T extends ControlSplitNode> T append(T fixed) {
-                assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
-                assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-                T added = currentGraph.add(fixed);
-                lastInstr.setNext(added);
-                lastInstr = null;
+            public <T extends ValueNode> T recursiveAppend(T v) {
+                if (v.graph() != null) {
+                    return v;
+                }
+                T added = currentGraph.addOrUniqueWithInputs(v);
+                if (added == v) {
+                    updateLastInstruction(v);
+                }
                 return added;
             }
 
-            public <T extends FixedWithNextNode> T append(T fixed) {
-                assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
-                assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-                T added = currentGraph.add(fixed);
-                lastInstr.setNext(added);
-                lastInstr = added;
-                return added;
-            }
-
-            public <T extends FloatingNode> T append(T v) {
-                if (v.graph() != null) {
-                    return v;
+            private <T extends ValueNode> void updateLastInstruction(T v) {
+                if (v instanceof FixedNode) {
+                    FixedNode fixedNode = (FixedNode) v;
+                    lastInstr.setNext(fixedNode);
+                    if (fixedNode instanceof FixedWithNextNode) {
+                        FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                        assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                        lastInstr = fixedWithNextNode;
+                    } else {
+                        lastInstr = null;
+                    }
                 }
-                T added = currentGraph.unique(v);
-                return added;
             }
 
             private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) {
@@ -2362,7 +2471,8 @@
                     if (bp != this) {
                         fmt.format("%n%s", indent);
                     }
-                    fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bci(), bp.parsingReplacement());
+                    fmt.format("%s [bci: %d, replacement: %s]", bp.method.asStackTraceElement(bp.bci()), bp.bci(), bp.parsingReplacement());
+                    fmt.format("%n%s", new BytecodeDisassembler().disassemble(bp.method, bp.bci(), bp.bci() + 10));
                     bp = bp.parent;
                     indent += " ";
                 }
@@ -2392,4 +2502,11 @@
     static String nSpaces(int n) {
         return n == 0 ? "" : format("%" + n + "s", "");
     }
+
+    @SuppressWarnings("all")
+    private static boolean assertionsEnabled() {
+        boolean assertionsEnabled = false;
+        assert assertionsEnabled = true;
+        return assertionsEnabled;
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon Mar 23 16:11:48 2015 +0100
@@ -43,8 +43,8 @@
 
 public final class HIRFrameStateBuilder {
 
-    private static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
-    private static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
+    static final ValueNode[] EMPTY_ARRAY = new ValueNode[0];
+    static final MonitorIdNode[] EMPTY_MONITOR_ARRAY = new MonitorIdNode[0];
 
     protected final BytecodeParser parser;
     protected final ResolvedJavaMethod method;
@@ -145,6 +145,14 @@
             javaIndex += kind.getSlotCount();
             index++;
         }
+
+        if (parser.replacementContext instanceof IntrinsicContext) {
+            IntrinsicContext intrinsic = (IntrinsicContext) parser.replacementContext;
+            if (intrinsic.isCompilationRoot()) {
+                // Records the parameters to an root compiled intrinsic
+                intrinsic.args = locals.clone();
+            }
+        }
     }
 
     private HIRFrameStateBuilder(HIRFrameStateBuilder other) {
@@ -200,28 +208,20 @@
         if (parser.parsingReplacement()) {
             IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic();
             if (intrinsic != null) {
-                assert parent != null : "intrinsics can only be processed in context of a caller";
-
-                // We're somewhere in an intrinsic. In this case, we want a frame state
-                // that will restart the interpreter just before the intrinsified
-                // invocation.
-                return intrinsic.getInvokeStateBefore(parent);
+                return intrinsic.getInvokeStateBefore(parser.getGraph(), parent);
             }
         }
+        // If this is the recursive call in a partial intrinsification
+        // the frame(s) of the intrinsic method are omitted
+        while (parent != null && parent.parsingReplacement() && parent.replacementContext.asIntrinsic() != null) {
+            parent = parent.getParent();
+        }
         return create(bci, parent, false);
     }
 
     public FrameState create(int bci, BytecodeParser parent, boolean duringCall) {
         if (outerFrameState == null && parent != null) {
             outerFrameState = parent.getFrameState().create(parent.bci());
-            if (parser.parsingReplacement()) {
-                IntrinsicContext intrinsic = parser.replacementContext.asIntrinsic();
-                if (intrinsic != null) {
-                    // A side-effect of creating the frame state in a replacing
-                    // parent is that the 'during' frame state is created as well
-                    outerFrameState = intrinsic.getInvokeStateDuring();
-                }
-            }
         }
         if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
             FrameState newFrameState = outerFrameState.duplicateModified(outerFrameState.bci, true, Kind.Void, this.peek(0));
@@ -297,7 +297,7 @@
             ((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";
+            assert !(block instanceof LoopBeginNode) : String.format("Phi functions for loop headers are create eagerly for changed locals and all stack slots: %s != %s", currentValue, otherValue);
             if (otherValue == null || otherValue.isDeleted() || currentValue.getKind() != otherValue.getKind()) {
                 return null;
             }
@@ -958,4 +958,17 @@
         }
         return false;
     }
+
+    public void replace(ValueNode oldValue, ValueNode newValue) {
+        for (int i = 0; i < locals.length; i++) {
+            if (locals[i] == oldValue) {
+                locals[i] = newValue;
+            }
+        }
+        for (int i = 0; i < stackSize; i++) {
+            if (stack[i] == oldValue) {
+                stack[i] = newValue;
+            }
+        }
+    }
 }
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Mon Mar 23 16:11:48 2015 +0100
@@ -35,7 +35,7 @@
     }
 
     public static double test(double arg) throws NaN {
-        double v = Math.sin(arg);
+        double v = Math.sin(arg) * Math.sin(arg * 5);
         if (Double.isNaN(v)) {
             // NaN can't be tested against itself
             throw new NaN();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Binary.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,283 @@
+/*
+ * 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.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.CompilationResult.DataSectionReference;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * AMD64 LIR instructions that have two inputs and one output.
+ */
+public class AMD64Binary {
+
+    /**
+     * Instruction that has two {@link AllocatableValue} operands.
+     */
+    public static class Op extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<Op> TYPE = LIRInstructionClass.create(Op.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Alive({REG, STACK}) protected AllocatableValue y;
+
+        public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            if (isRegister(y)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y));
+            }
+        }
+    }
+
+    /**
+     * Commutative instruction that has two {@link AllocatableValue} operands.
+     */
+    public static class CommutativeOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<CommutativeOp> TYPE = LIRInstructionClass.create(CommutativeOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public CommutativeOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AllocatableValue input;
+            if (sameRegister(result, y)) {
+                input = x;
+            } else {
+                AMD64Move.move(crb, masm, result, x);
+                input = y;
+            }
+
+            if (isRegister(input)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(input));
+            } else {
+                assert isStackSlot(input);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
+            }
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand.
+     */
+    public static class ConstOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
+
+        @Opcode private final AMD64MIOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        private final int y;
+
+        public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
+            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, result, x, y);
+        }
+
+        public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            opcode.emit(masm, size, asRegister(result), y);
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one
+     * {@link DataSectionReference} operand.
+     */
+    public static class DataOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        private final JavaConstant y;
+
+        private final int alignment;
+
+        public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
+            this(opcode, size, result, x, y, y.getKind().getByteCount());
+        }
+
+        public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+
+            this.alignment = alignment;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one {@link AMD64AddressValue
+     * memory} operand.
+     */
+    public static class MemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryOp> TYPE = LIRInstructionClass.create(MemoryOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        @Alive({COMPOSITE}) protected AMD64AddressValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, x);
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(result), y.toAddress());
+        }
+
+        @Override
+        public void verify() {
+            super.verify();
+            assert differentRegisters(result, y) || sameRegister(x, y);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction with a separate result operand, one {@link AllocatableValue} input and one 32-bit
+     * immediate input.
+     */
+    public static class RMIOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<RMIOp> TYPE = LIRInstructionClass.create(RMIOp.class);
+
+        @Opcode private final AMD64RMIOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue x;
+        private final int y;
+
+        public RMIOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, int y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(x)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(x), y);
+            } else {
+                assert isStackSlot(x);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), y);
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryCommutativeOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64BinaryCommutativeOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64BinaryCommutativeOp> TYPE = LIRInstructionClass.create(AMD64BinaryCommutativeOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Def({REG, HINT}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    @Use({REG, STACK}) protected AllocatableValue y;
-
-    public AMD64BinaryCommutativeOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AllocatableValue input;
-        if (sameRegister(result, y)) {
-            input = x;
-        } else {
-            AMD64Move.move(crb, masm, result, x);
-            input = y;
-        }
-
-        if (isRegister(input)) {
-            opcode.emit(masm, size, asRegister(result), asRegister(input));
-        } else {
-            assert isStackSlot(input);
-            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(input));
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64BinaryConstOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64BinaryConstOp> TYPE = LIRInstructionClass.create(AMD64BinaryConstOp.class);
-
-    @Opcode private final AMD64MIOp opcode;
-    private final OperandSize size;
-
-    @Def({REG, HINT}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    protected JavaConstant y;
-
-    public AMD64BinaryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-        this(opcode.getMIOpcode(size, NumUtil.isByte(y.asLong())), size, result, x, y);
-    }
-
-    public AMD64BinaryConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Move.move(crb, masm, result, x);
-        assert NumUtil.is32bit(y.asLong());
-        opcode.emit(masm, size, asRegister(result), (int) y.asLong());
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryConsumer.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,293 @@
+/*
+ * 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.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.code.CompilationResult.DataSectionReference;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * AMD64 LIR instructions that have two input operands, but no output operand.
+ */
+public class AMD64BinaryConsumer {
+
+    /**
+     * Instruction that has two {@link AllocatableValue} operands.
+     */
+    public static class Op extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<Op> TYPE = LIRInstructionClass.create(Op.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Use({REG}) protected AllocatableValue x;
+        @Use({REG, STACK}) protected AllocatableValue y;
+
+        public Op(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(y)) {
+                opcode.emit(masm, size, asRegister(x), asRegister(y));
+            } else {
+                assert isStackSlot(y);
+                opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y));
+            }
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one 32-bit immediate operand.
+     */
+    public static class ConstOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<ConstOp> TYPE = LIRInstructionClass.create(ConstOp.class);
+
+        @Opcode private final AMD64MIOp opcode;
+        private final OperandSize size;
+
+        @Use({REG, STACK}) protected AllocatableValue x;
+        private final int y;
+
+        public ConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AllocatableValue x, int y) {
+            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y);
+        }
+
+        public ConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) {
+            this(TYPE, opcode, size, x, y);
+        }
+
+        protected ConstOp(LIRInstructionClass<? extends ConstOp> c, AMD64MIOp opcode, OperandSize size, AllocatableValue x, int y) {
+            super(c);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(x)) {
+                opcode.emit(masm, size, asRegister(x), y);
+            } else {
+                assert isStackSlot(x);
+                opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), y);
+            }
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AllocatableValue} operand and one
+     * {@link DataSectionReference} operand.
+     */
+    public static class DataOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<DataOp> TYPE = LIRInstructionClass.create(DataOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Use({REG}) protected AllocatableValue x;
+        private final Constant y;
+
+        private final int alignment;
+
+        public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y) {
+            this(opcode, size, x, y, size.getBytes());
+        }
+
+        public DataOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, Constant y, int alignment) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.alignment = alignment;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
+        }
+    }
+
+    /**
+     * Instruction that has an {@link AllocatableValue} as first input and a
+     * {@link AMD64AddressValue memory} operand as second input.
+     */
+    public static class MemoryRMOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryRMOp> TYPE = LIRInstructionClass.create(MemoryRMOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Use({REG}) protected AllocatableValue x;
+        @Use({COMPOSITE}) protected AMD64AddressValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(x), y.toAddress());
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction that has a {@link AMD64AddressValue memory} operand as first input and an
+     * {@link AllocatableValue} as second input.
+     */
+    public static class MemoryMROp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryMROp> TYPE = LIRInstructionClass.create(MemoryMROp.class);
+
+        @Opcode private final AMD64MROp opcode;
+        private final OperandSize size;
+
+        @Use({COMPOSITE}) protected AMD64AddressValue x;
+        @Use({REG}) protected AllocatableValue y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryMROp(AMD64MROp opcode, OperandSize size, AMD64AddressValue x, AllocatableValue y, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, x.toAddress(), asRegister(y));
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Instruction that has one {@link AMD64AddressValue memory} operand and one 32-bit immediate
+     * operand.
+     */
+    public static class MemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryConstOp> TYPE = LIRInstructionClass.create(MemoryConstOp.class);
+
+        @Opcode private final AMD64MIOp opcode;
+        private final OperandSize size;
+
+        @Use({COMPOSITE}) protected AMD64AddressValue x;
+        private final int y;
+
+        @State protected LIRFrameState state;
+
+        public MemoryConstOp(AMD64BinaryArithmetic opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
+            this(opcode.getMIOpcode(size, NumUtil.isByte(y)), size, x, y, state);
+        }
+
+        public MemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
+            this(TYPE, opcode, size, x, y, state);
+        }
+
+        protected MemoryConstOp(LIRInstructionClass<? extends MemoryConstOp> c, AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, int y, LIRFrameState state) {
+            super(c);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.x = x;
+            this.y = y;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, x.toAddress(), y);
+        }
+
+        @Override
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryMemoryOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64BinaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
-    public static final LIRInstructionClass<AMD64BinaryMemoryOp> TYPE = LIRInstructionClass.create(AMD64BinaryMemoryOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Def({REG, HINT}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    @Alive({COMPOSITE}) protected AMD64AddressValue y;
-
-    @State protected LIRFrameState state;
-
-    public AMD64BinaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-
-        this.state = state;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Move.move(crb, masm, result, x);
-        if (state != null) {
-            crb.recordImplicitException(masm.position(), state);
-        }
-        opcode.emit(masm, size, asRegister(result), y.toAddress());
-    }
-
-    @Override
-    public void verify() {
-        super.verify();
-        assert differentRegisters(result, y) || sameRegister(x, y);
-    }
-
-    @Override
-    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-        if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
-            state = nullCheckState;
-            return true;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64BinaryOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64BinaryOp> TYPE = LIRInstructionClass.create(AMD64BinaryOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Def({REG, HINT}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    @Alive({REG, STACK}) protected AllocatableValue y;
-
-    public AMD64BinaryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, AllocatableValue y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Move.move(crb, masm, result, x);
-        if (isRegister(y)) {
-            opcode.emit(masm, size, asRegister(result), asRegister(y));
-        } else {
-            assert isStackSlot(y);
-            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(y));
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64BinaryPatchOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64BinaryPatchOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64BinaryPatchOp> TYPE = LIRInstructionClass.create(AMD64BinaryPatchOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Def({REG, HINT}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    protected JavaConstant y;
-
-    private final int alignment;
-
-    public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-        this(opcode, size, result, x, y, y.getKind().getByteCount());
-    }
-
-    public AMD64BinaryPatchOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y, int alignment) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-
-        this.alignment = alignment;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Move.move(crb, masm, result, x);
-        opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.recordDataReferenceInCode(y, alignment));
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64CompareConstOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64CompareConstOp> TYPE = LIRInstructionClass.create(AMD64CompareConstOp.class);
-
-    @Opcode private final AMD64MIOp opcode;
-    private final OperandSize size;
-
-    @Use({REG, STACK}) protected AllocatableValue x;
-    protected JavaConstant y;
-
-    public AMD64CompareConstOp(AMD64MIOp opcode, OperandSize size, AllocatableValue x, JavaConstant y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        assert NumUtil.is32bit(y.asLong());
-        if (isRegister(x)) {
-            opcode.emit(masm, size, asRegister(x), (int) y.asLong());
-        } else {
-            assert isStackSlot(x);
-            opcode.emit(masm, size, (AMD64Address) crb.asAddress(x), (int) y.asLong());
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +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.amd64;
-
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64CompareMemoryConstOp extends AMD64LIRInstruction implements ImplicitNullCheck {
-    public static final LIRInstructionClass<AMD64CompareMemoryConstOp> TYPE = LIRInstructionClass.create(AMD64CompareMemoryConstOp.class);
-
-    @Opcode private final AMD64MIOp opcode;
-    private final OperandSize size;
-
-    @Use({COMPOSITE}) protected AMD64AddressValue x;
-    protected JavaConstant y;
-
-    @State protected LIRFrameState state;
-
-    public AMD64CompareMemoryConstOp(AMD64MIOp opcode, OperandSize size, AMD64AddressValue x, JavaConstant y, LIRFrameState state) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.x = x;
-        this.y = y;
-
-        this.state = state;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (state != null) {
-            crb.recordImplicitException(masm.position(), state);
-        }
-        assert NumUtil.is32bit(y.asLong());
-        opcode.emit(masm, size, x.toAddress(), (int) y.asLong());
-    }
-
-    @Override
-    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-        if (state == null && x.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
-            state = nullCheckState;
-            return true;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareMemoryOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64CompareMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
-    public static final LIRInstructionClass<AMD64CompareMemoryOp> TYPE = LIRInstructionClass.create(AMD64CompareMemoryOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Use({REG}) protected AllocatableValue x;
-    @Use({COMPOSITE}) protected AMD64AddressValue y;
-
-    @State protected LIRFrameState state;
-
-    public AMD64CompareMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AMD64AddressValue y, LIRFrameState state) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.x = x;
-        this.y = y;
-
-        this.state = state;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (state != null) {
-            crb.recordImplicitException(masm.position(), state);
-        }
-        opcode.emit(masm, size, asRegister(x), y.toAddress());
-    }
-
-    @Override
-    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-        if (state == null && y.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
-            state = nullCheckState;
-            return true;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64CompareOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64CompareOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64CompareOp> TYPE = LIRInstructionClass.create(AMD64CompareOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Use({REG}) protected AllocatableValue x;
-    @Use({REG, STACK}) protected AllocatableValue y;
-
-    public AMD64CompareOp(AMD64RMOp opcode, OperandSize size, AllocatableValue x, AllocatableValue y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (isRegister(y)) {
-            opcode.emit(masm, size, asRegister(x), asRegister(y));
-        } else {
-            assert isStackSlot(y);
-            opcode.emit(masm, size, asRegister(x), (AMD64Address) crb.asAddress(y));
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Move.java	Mon Mar 23 16:11:48 2015 +0100
@@ -30,11 +30,9 @@
 import com.oracle.graal.amd64.*;
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.amd64.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
 import com.oracle.graal.lir.StandardOp.MoveOp;
 import com.oracle.graal.lir.StandardOp.NullCheck;
 import com.oracle.graal.lir.asm.*;
@@ -110,210 +108,6 @@
         }
     }
 
-    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(LIRInstructionClass<? extends MemOp> c, Kind kind, AMD64AddressValue address, LIRFrameState state) {
-            super(c);
-            this.kind = kind;
-            this.address = address;
-            this.state = state;
-        }
-
-        protected abstract void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm);
-
-        @Override
-        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            if (state != null) {
-                crb.recordImplicitException(masm.position(), state);
-            }
-            emitMemAccess(crb, masm);
-        }
-
-        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-            if (state == null && value.equals(address.base) && address.index.equals(Value.ILLEGAL) && address.displacement >= 0 && address.displacement < implicitNullCheckLimit) {
-                state = nullCheckState;
-                return true;
-            }
-            return false;
-        }
-    }
-
-    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(TYPE, kind, address, state);
-            this.result = result;
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            switch (kind) {
-                case Boolean:
-                    masm.movzbl(asRegister(result), address.toAddress());
-                    break;
-                case Byte:
-                    masm.movsbl(asRegister(result), address.toAddress());
-                    break;
-                case Char:
-                    masm.movzwl(asRegister(result), address.toAddress());
-                    break;
-                case Short:
-                    masm.movswl(asRegister(result), address.toAddress());
-                    break;
-                case Int:
-                    masm.movl(asRegister(result), address.toAddress());
-                    break;
-                case Long:
-                    masm.movq(asRegister(result), address.toAddress());
-                    break;
-                case Float:
-                    masm.movflt(asFloatReg(result), address.toAddress());
-                    break;
-                case Double:
-                    masm.movdbl(asDoubleReg(result), address.toAddress());
-                    break;
-                case Object:
-                    masm.movq(asRegister(result), address.toAddress());
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
-    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(TYPE, kind, address, state);
-            this.result = result;
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            switch (kind) {
-                case Boolean:
-                case Byte:
-                    masm.movzbl(asRegister(result), address.toAddress());
-                    break;
-                case Char:
-                case Short:
-                    masm.movzwl(asRegister(result), address.toAddress());
-                    break;
-                case Int:
-                    masm.movl(asRegister(result), address.toAddress());
-                    break;
-                case Long:
-                    masm.movq(asRegister(result), address.toAddress());
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
-    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(TYPE, kind, address, state);
-            this.input = input;
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            assert isRegister(input);
-            switch (kind) {
-                case Boolean:
-                case Byte:
-                    masm.movb(address.toAddress(), asRegister(input));
-                    break;
-                case Char:
-                case Short:
-                    masm.movw(address.toAddress(), asRegister(input));
-                    break;
-                case Int:
-                    masm.movl(address.toAddress(), asRegister(input));
-                    break;
-                case Long:
-                    masm.movq(address.toAddress(), asRegister(input));
-                    break;
-                case Float:
-                    masm.movflt(address.toAddress(), asFloatReg(input));
-                    break;
-                case Double:
-                    masm.movsd(address.toAddress(), asDoubleReg(input));
-                    break;
-                case Object:
-                    masm.movq(address.toAddress(), asRegister(input));
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
-    public abstract static class StoreConstantOp extends MemOp {
-        public static final LIRInstructionClass<StoreConstantOp> TYPE = LIRInstructionClass.create(StoreConstantOp.class);
-
-        protected final JavaConstant input;
-
-        protected StoreConstantOp(LIRInstructionClass<? extends StoreConstantOp> c, Kind kind, AMD64AddressValue address, JavaConstant input, LIRFrameState state) {
-            super(c, kind, address, state);
-            this.input = input;
-        }
-
-        @Override
-        public void emitMemAccess(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-            switch (kind) {
-                case Boolean:
-                case Byte:
-                    masm.movb(address.toAddress(), input.asInt() & 0xFF);
-                    break;
-                case Char:
-                case Short:
-                    masm.movw(address.toAddress(), input.asInt() & 0xFFFF);
-                    break;
-                case Int:
-                    masm.movl(address.toAddress(), input.asInt());
-                    break;
-                case Long:
-                    if (NumUtil.isInt(input.asLong())) {
-                        masm.movslq(address.toAddress(), (int) input.asLong());
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                    }
-                    break;
-                case Float:
-                    masm.movl(address.toAddress(), floatToRawIntBits(input.asFloat()));
-                    break;
-                case Double:
-                    throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                case Object:
-                    if (input.isNull()) {
-                        masm.movptr(address.toAddress(), 0);
-                    } else {
-                        throw GraalInternalError.shouldNotReachHere("Cannot store 64-bit constants to memory");
-                    }
-                    break;
-                default:
-                    throw GraalInternalError.shouldNotReachHere();
-            }
-        }
-    }
-
     public static final class LeaOp extends AMD64LIRInstruction {
         public static final LIRInstructionClass<LeaOp> TYPE = LIRInstructionClass.create(LeaOp.class);
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64MulConstOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64MulConstOp> TYPE = LIRInstructionClass.create(AMD64MulConstOp.class);
-
-    @Opcode private final AMD64RMIOp opcode;
-    private final OperandSize size;
-
-    @Def({REG}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    protected JavaConstant y;
-
-    public AMD64MulConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        assert NumUtil.isInt(y.asLong());
-        int imm = (int) y.asLong();
-        if (isRegister(x)) {
-            opcode.emit(masm, size, asRegister(result), asRegister(x), imm);
-        } else {
-            assert isStackSlot(x);
-            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), imm);
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64MulDivOp.java	Mon Mar 23 16:11:48 2015 +0100
@@ -34,6 +34,10 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
+/**
+ * AMD64 mul/div operation. This operation has a single operand for the second input. The first
+ * input must be in RAX for mul and in RDX:RAX for div. The result is in RDX:RAX.
+ */
 public class AMD64MulDivOp extends AMD64LIRInstruction {
     public static final LIRInstructionClass<AMD64MulDivOp> TYPE = LIRInstructionClass.create(AMD64MulDivOp.class);
 
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64RegStackConstOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMIOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64RegStackConstOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64RegStackConstOp> TYPE = LIRInstructionClass.create(AMD64RegStackConstOp.class);
-
-    @Opcode private final AMD64RMIOp opcode;
-    private final OperandSize size;
-
-    @Def({REG}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue x;
-    protected JavaConstant y;
-
-    public AMD64RegStackConstOp(AMD64RMIOp opcode, OperandSize size, AllocatableValue result, AllocatableValue x, JavaConstant y) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.x = x;
-        this.y = y;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        assert NumUtil.is32bit(y.asLong());
-        if (isRegister(x)) {
-            opcode.emit(masm, size, asRegister(result), asRegister(x), (int) y.asLong());
-        } else {
-            assert isStackSlot(x);
-            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(x), (int) y.asLong());
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64ShiftOp.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,6 +33,10 @@
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 
+/**
+ * AMD64 shift/rotate operation. This operation has a single operand for the first input and output.
+ * The second input must be in the RCX register.
+ */
 public class AMD64ShiftOp extends AMD64LIRInstruction {
     public static final LIRInstructionClass<AMD64ShiftOp> TYPE = LIRInstructionClass.create(AMD64ShiftOp.class);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64Unary.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,176 @@
+/*
+ * 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.amd64;
+
+import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.amd64.*;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
+import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
+import com.oracle.graal.lir.asm.*;
+
+/**
+ * AMD64 LIR instructions that have one input and one output.
+ */
+public class AMD64Unary {
+
+    /**
+     * Instruction with a single operand that is both input and output.
+     */
+    public static class MOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MOp> TYPE = LIRInstructionClass.create(MOp.class);
+
+        @Opcode private final AMD64MOp opcode;
+        private final OperandSize size;
+
+        @Def({REG, HINT}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue value;
+
+        public MOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            AMD64Move.move(crb, masm, result, value);
+            opcode.emit(masm, size, asRegister(result));
+        }
+    }
+
+    /**
+     * Instruction with separate input and output operands, and an operand encoding of RM.
+     */
+    public static class RMOp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<RMOp> TYPE = LIRInstructionClass.create(RMOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({REG, STACK}) protected AllocatableValue value;
+
+        public RMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(value)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(value));
+            } else {
+                assert isStackSlot(value);
+                opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value));
+            }
+        }
+    }
+
+    /**
+     * Instruction with separate input and output operands, and an operand encoding of MR.
+     */
+    public static class MROp extends AMD64LIRInstruction {
+        public static final LIRInstructionClass<MROp> TYPE = LIRInstructionClass.create(MROp.class);
+
+        @Opcode private final AMD64MROp opcode;
+        private final OperandSize size;
+
+        @Def({REG, STACK}) protected AllocatableValue result;
+        @Use({REG}) protected AllocatableValue value;
+
+        public MROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.value = value;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (isRegister(result)) {
+                opcode.emit(masm, size, asRegister(result), asRegister(value));
+            } else {
+                assert isStackSlot(result);
+                opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value));
+            }
+        }
+    }
+
+    /**
+     * Instruction with a {@link AMD64AddressValue memory} operand.
+     */
+    public static class MemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
+        public static final LIRInstructionClass<MemoryOp> TYPE = LIRInstructionClass.create(MemoryOp.class);
+
+        @Opcode private final AMD64RMOp opcode;
+        private final OperandSize size;
+
+        @Def({REG}) protected AllocatableValue result;
+        @Use({COMPOSITE}) protected AMD64AddressValue input;
+
+        @State protected LIRFrameState state;
+
+        public MemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) {
+            super(TYPE);
+            this.opcode = opcode;
+            this.size = size;
+
+            this.result = result;
+            this.input = input;
+
+            this.state = state;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            if (state != null) {
+                crb.recordImplicitException(masm.position(), state);
+            }
+            opcode.emit(masm, size, asRegister(result), input.toAddress());
+        }
+
+        public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
+            if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
+                state = nullCheckState;
+                return true;
+            }
+            return false;
+        }
+    }
+}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64UnaryMOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64UnaryMOp> TYPE = LIRInstructionClass.create(AMD64UnaryMOp.class);
-
-    @Opcode private final AMD64MOp opcode;
-    private final OperandSize size;
-
-    @Def({REG, HINT}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue value;
-
-    public AMD64UnaryMOp(AMD64MOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.value = value;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        AMD64Move.move(crb, masm, result, value);
-        opcode.emit(masm, size, asRegister(result));
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMROp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64MROp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64UnaryMROp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64UnaryMROp> TYPE = LIRInstructionClass.create(AMD64UnaryMROp.class);
-
-    @Opcode private final AMD64MROp opcode;
-    private final OperandSize size;
-
-    @Def({REG, STACK}) protected AllocatableValue result;
-    @Use({REG}) protected AllocatableValue value;
-
-    public AMD64UnaryMROp(AMD64MROp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.value = value;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (isRegister(result)) {
-            opcode.emit(masm, size, asRegister(result), asRegister(value));
-        } else {
-            assert isStackSlot(result);
-            opcode.emit(masm, size, (AMD64Address) crb.asAddress(result), asRegister(value));
-        }
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryMemoryOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64UnaryMemoryOp extends AMD64LIRInstruction implements ImplicitNullCheck {
-    public static final LIRInstructionClass<AMD64UnaryMemoryOp> TYPE = LIRInstructionClass.create(AMD64UnaryMemoryOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Def({REG}) protected AllocatableValue result;
-    @Use({COMPOSITE}) protected AMD64AddressValue input;
-
-    @State protected LIRFrameState state;
-
-    public AMD64UnaryMemoryOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AMD64AddressValue input, LIRFrameState state) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.input = input;
-
-        this.state = state;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (state != null) {
-            crb.recordImplicitException(masm.position(), state);
-        }
-        opcode.emit(masm, size, asRegister(result), input.toAddress());
-    }
-
-    public boolean makeNullCheckFor(Value value, LIRFrameState nullCheckState, int implicitNullCheckLimit) {
-        if (state == null && input.isValidImplicitNullCheckFor(value, implicitNullCheckLimit)) {
-            state = nullCheckState;
-            return true;
-        }
-        return false;
-    }
-}
--- a/graal/com.oracle.graal.lir.amd64/src/com/oracle/graal/lir/amd64/AMD64UnaryRMOp.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +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.amd64;
-
-import static com.oracle.graal.api.code.ValueUtil.*;
-import static com.oracle.graal.lir.LIRInstruction.OperandFlag.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.asm.amd64.AMD64Assembler.AMD64RMOp;
-import com.oracle.graal.asm.amd64.AMD64Assembler.OperandSize;
-import com.oracle.graal.asm.amd64.*;
-import com.oracle.graal.lir.*;
-import com.oracle.graal.lir.asm.*;
-
-public class AMD64UnaryRMOp extends AMD64LIRInstruction {
-    public static final LIRInstructionClass<AMD64UnaryRMOp> TYPE = LIRInstructionClass.create(AMD64UnaryRMOp.class);
-
-    @Opcode private final AMD64RMOp opcode;
-    private final OperandSize size;
-
-    @Def({REG}) protected AllocatableValue result;
-    @Use({REG, STACK}) protected AllocatableValue value;
-
-    public AMD64UnaryRMOp(AMD64RMOp opcode, OperandSize size, AllocatableValue result, AllocatableValue value) {
-        super(TYPE);
-        this.opcode = opcode;
-        this.size = size;
-
-        this.result = result;
-        this.value = value;
-    }
-
-    @Override
-    public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
-        if (isRegister(value)) {
-            opcode.emit(masm, size, asRegister(result), asRegister(value));
-        } else {
-            assert isStackSlot(value);
-            opcode.emit(masm, size, asRegister(result), (AMD64Address) crb.asAddress(value));
-        }
-    }
-}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Mon Mar 23 16:11:48 2015 +0100
@@ -349,6 +349,11 @@
                 if (vpn.hasNoUsages()) {
                     continue;
                 }
+                if (vpn.value() == null) {
+                    assert vpn instanceof GuardProxyNode;
+                    vpn.replaceAtUsages(null);
+                    continue;
+                }
                 final ValueNode replaceWith;
                 ValueNode newVpn = prim(newEarlyExitIsLoopExit ? vpn : vpn.value());
                 if (newVpn != null) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -37,7 +37,7 @@
 /**
  * The {@code ConstantNode} represents a {@link Constant constant}.
  */
-@NodeInfo(shortName = "Const", nameTemplate = "Const({p#rawvalue})")
+@NodeInfo(nameTemplate = "C({p#rawvalue})")
 public final class ConstantNode extends FloatingNode implements LIRLowerable {
 
     public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -25,7 +25,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodeinfo.*;
 
-@NodeInfo(allowedUsageTypes = {InputType.Association})
+@NodeInfo(allowedUsageTypes = {InputType.Association}, nameTemplate = "End")
 public final class EndNode extends AbstractEndNode {
     public static final NodeClass<EndNode> TYPE = NodeClass.create(EndNode.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Mar 23 16:11:48 2015 +0100
@@ -40,7 +40,7 @@
  *
  * This can be used as debug or deoptimization information.
  */
-@NodeInfo(nameTemplate = "FrameState@{p#method/s}:{p#bci}")
+@NodeInfo(nameTemplate = "@{p#method/s}:{p#bci}")
 public final class FrameState extends VirtualState implements IterableNodeType {
     public static final NodeClass<FrameState> TYPE = NodeClass.create(FrameState.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 
-@NodeInfo(allowedUsageTypes = {InputType.Guard})
+@NodeInfo(allowedUsageTypes = {InputType.Guard}, nameTemplate = "Proxy({i#value})")
 public final class GuardProxyNode extends ProxyNode implements GuardingNode, Proxy, LIRLowerable {
 
     public static final NodeClass<GuardProxyNode> TYPE = NodeClass.create(GuardProxyNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -22,10 +22,6 @@
  */
 package com.oracle.graal.nodes;
 
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.compiler.common.type.StampFactory.*;
-
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
@@ -70,21 +66,6 @@
         return action;
     }
 
-    /**
-     * Returns a node whose stamp is guaranteed to be {@linkplain StampTool#isPointerNonNull(Stamp)
-     * non-null}. If {@code value} already has such a stamp, then it is returned. Otherwise a fixed
-     * node guarding {@code value} is returned where the guard performs a null check.
-     */
-    public static ValueNode nullCheckedValue(ValueNode value) {
-        ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
-        if (!StampTool.isPointerNonNull(receiverStamp)) {
-            IsNullNode condition = value.graph().unique(new IsNullNode(value));
-            Stamp stamp = receiverStamp.join(objectNonNull());
-            return new GuardingPiNode(value, condition, true, NullCheckException, InvalidateReprofile, stamp);
-        }
-        return value;
-    }
-
     public GuardingPiNode(ValueNode object) {
         this(object, object.graph().unique(new IsNullNode(object)), true, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, object.stamp().join(StampFactory.objectNonNull()));
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -31,7 +31,7 @@
 /**
  * Memory {@code PhiNode}s merge memory dependencies at control flow merges.
  */
-@NodeInfo(nameTemplate = "MemoryPhi({i#values}) {p#locationIdentity/s}", allowedUsageTypes = {InputType.Memory})
+@NodeInfo(nameTemplate = "Φ({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);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -31,7 +31,7 @@
 /**
  * The {@code Parameter} instruction is a placeholder for an incoming argument to a function call.
  */
-@NodeInfo(nameTemplate = "Param({p#index})")
+@NodeInfo(nameTemplate = "P({p#index})")
 public final class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider {
 
     public static final NodeClass<ParameterNode> TYPE = NodeClass.create(ParameterNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -30,7 +30,7 @@
 /**
  * The start node of a graph.
  */
-@NodeInfo(allowedUsageTypes = {InputType.Memory})
+@NodeInfo(allowedUsageTypes = {InputType.Memory}, nameTemplate = "Start")
 public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint.Single {
     public static final NodeClass<StartNode> TYPE = NodeClass.create(StartNode.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -30,7 +30,7 @@
 /**
  * Value {@link PhiNode}s merge data flow values at control flow merges.
  */
-@NodeInfo(nameTemplate = "ValuePhi({i#values})")
+@NodeInfo(nameTemplate = "Φ({i#values})")
 public class ValuePhiNode extends PhiNode {
 
     public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.spi.*;
 
-@NodeInfo
+@NodeInfo(nameTemplate = "Proxy({i#value})")
 public final class ValueProxyNode extends ProxyNode implements Canonicalizable, Virtualizable, ValueProxy {
 
     public static final NodeClass<ValueProxyNode> TYPE = NodeClass.create(ValueProxyNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -36,7 +36,7 @@
  * Location node that is the sum of two other location nodes. Can represent locations in the form of
  * [(base + x) + y] where base is a node and x and y are location nodes.
  */
-@NodeInfo(nameTemplate = "AddLoc {p#locationIdentity/s}")
+@NodeInfo(nameTemplate = "&+({p#locationIdentity/s})")
 public final class AddLocationNode extends LocationNode implements Canonicalizable.Binary<LocationNode> {
 
     public static final NodeClass<AddLocationNode> TYPE = NodeClass.create(AddLocationNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,7 +33,7 @@
  * Location node that has a constant displacement. Can represent addresses of the form [base + disp]
  * where base is a node and disp is a constant.
  */
-@NodeInfo(nameTemplate = "Loc {p#locationIdentity/s}")
+@NodeInfo(nameTemplate = "&({p#locationIdentity/s})")
 public final class ConstantLocationNode extends LocationNode {
 
     public static final NodeClass<ConstantLocationNode> TYPE = NodeClass.create(ConstantLocationNode.class);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -37,7 +37,7 @@
  * [base + index * scale + disp] where base and index are nodes and scale and disp are integer
  * constants.
  */
-@NodeInfo(nameTemplate = "IdxLoc {p#locationIdentity/s}")
+@NodeInfo(nameTemplate = "&({p#locationIdentity/s})[{i#index}]")
 public final class IndexedLocationNode extends LocationNode implements Canonicalizable {
     public static final NodeClass<IndexedLocationNode> TYPE = NodeClass.create(IndexedLocationNode.class);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfDynamicNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -28,7 +28,6 @@
 import com.oracle.graal.nodeinfo.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * The {@code InstanceOfDynamicNode} represents a type check where the type being checked is not
@@ -56,8 +55,6 @@
         this.mirror = mirror;
         this.object = object;
         assert mirror.getKind() == Kind.Object : mirror.getKind();
-        assert StampTool.isExactType(mirror);
-        assert StampTool.typeOrNull(mirror).getName().equals("Ljava/lang/Class;");
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -37,7 +37,7 @@
 /**
  * The {@code LoadFieldNode} represents a read of a static or instance field.
  */
-@NodeInfo(nameTemplate = "LoadField#{p#field/s}")
+@NodeInfo(nameTemplate = "#{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);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,8 +33,6 @@
  * Interface for managing replacements.
  */
 public interface Replacements {
-    // Disabled until bug in support for this is fixed.
-    boolean SELF_RECURSIVE_INTRINSICS_ENABLED = false;
 
     /**
      * Gets the snippet graph derived from a given method.
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Mon Mar 23 16:11:48 2015 +0100
@@ -91,7 +91,7 @@
 
     private static void iterateSuccessorsAndInputs(NodeFlood flood) {
         BiConsumer<Node, Node> consumer = (n, succOrInput) -> {
-            assert succOrInput.isAlive() : succOrInput;
+            assert succOrInput.isAlive() : "dead successor or input " + succOrInput + " in " + n;
             flood.add(succOrInput);
         };
         for (Node current : flood) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon Mar 23 16:11:48 2015 +0100
@@ -32,6 +32,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.compiler.common.type.*;
 import com.oracle.graal.debug.*;
@@ -432,14 +433,18 @@
                     frameState.replaceAndDelete(stateAfterException);
                 } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
                     handleMissingAfterExceptionFrameState(frameState);
+                } else if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
+                    // This is an intrinsic. Deoptimizing within an intrinsic
+                    // must re-execute the intrinsified invocation
+                    assert frameState.outerFrameState() == null;
+                    NodeInputList<ValueNode> invokeArgsList = invoke.callTarget().arguments();
+                    ValueNode[] invokeArgs = invokeArgsList.isEmpty() ? NO_ARGS : invokeArgsList.toArray(new ValueNode[invokeArgsList.size()]);
+                    FrameState stateBeforeCall = stateAtReturn.duplicateModifiedBeforeCall(invoke.bci(), invokeReturnKind, invokeArgs);
+                    frameState.replaceAndDelete(stateBeforeCall);
                 } else {
                     // only handle the outermost frame states
                     if (frameState.outerFrameState() == null) {
-                        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
-                        assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
-                        assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState;
-                        assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState;
-                        assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method()) : frameState;
+                        assert checkInlineeFrameState(invoke, inlineGraph, frameState);
                         if (outerFrameState == null) {
                             outerFrameState = stateAtReturn.duplicateModifiedDuringCall(invoke.bci(), invokeReturnKind);
                         }
@@ -450,6 +455,32 @@
         }
     }
 
+    static boolean checkInlineeFrameState(Invoke invoke, StructuredGraph inlineGraph, FrameState frameState) {
+        assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI : frameState;
+        assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+        assert frameState.bci != BytecodeFrame.UNKNOWN_BCI : frameState;
+        assert frameState.bci != BytecodeFrame.UNWIND_BCI : frameState;
+        if (frameState.bci != BytecodeFrame.INVALID_FRAMESTATE_BCI) {
+            if (frameState.method().equals(inlineGraph.method())) {
+                // Normal inlining expects all outermost inlinee frame states to
+                // denote the inlinee method
+            } else if (frameState.method().equals(invoke.callTarget().targetMethod())) {
+                // This occurs when an intrinsic calls back to the original
+                // method to handle a slow path. During parsing of such a
+                // partial intrinsic, these calls are given frame states
+                // that exclude the outer frame state denoting a position
+                // in the intrinsic code.
+                assert inlineGraph.method().getAnnotation(MethodSubstitution.class) != null : "expected an intrinsic when inlinee frame state matches method of call target but does not match the method of the inlinee graph: " +
+                                frameState;
+            } else {
+                throw new AssertionError(frameState.toString());
+            }
+        }
+        return true;
+    }
+
+    private static final ValueNode[] NO_ARGS = {};
+
     private static boolean isStateAfterException(FrameState frameState) {
         return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
     }
@@ -543,7 +574,7 @@
     }
 
     public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
-        return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null;
+        return replacements.getMethodSubstitutionMethod(target) != null || getMacroNodeClass(replacements, target) != null;
     }
 
     public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/MemoryScheduleVerification.java	Mon Mar 23 16:11:48 2015 +0100
@@ -55,18 +55,17 @@
 
     @Override
     protected Set<FloatingReadNode> processBlock(Block block, Set<FloatingReadNode> currentState) {
+        AbstractBeginNode beginNode = block.getBeginNode();
+        if (beginNode instanceof AbstractMergeNode) {
+            AbstractMergeNode abstractMergeNode = (AbstractMergeNode) beginNode;
+            for (PhiNode phi : abstractMergeNode.phis()) {
+                if (phi instanceof MemoryPhiNode) {
+                    MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
+                    addFloatingReadUsages(currentState, memoryPhiNode);
+                }
+            }
+        }
         for (Node n : blockToNodesMap.get(block)) {
-            if (n instanceof AbstractMergeNode) {
-                AbstractMergeNode abstractMergeNode = (AbstractMergeNode) n;
-                for (PhiNode phi : abstractMergeNode.phis()) {
-                    if (phi instanceof MemoryPhiNode) {
-                        MemoryPhiNode memoryPhiNode = (MemoryPhiNode) phi;
-                        addFloatingReadUsages(currentState, memoryPhiNode);
-                    }
-                }
-
-            }
-
             if (n instanceof MemoryCheckpoint) {
                 if (n instanceof MemoryCheckpoint.Single) {
                     MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n;
@@ -88,7 +87,8 @@
                         // Floating read was found in the state.
                         currentState.remove(floatingReadNode);
                     } else {
-                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule");
+                        throw new RuntimeException("Floating read node " + n + " was not found in the state, i.e., it was killed by a memory check point before its place in the schedule. Block=" +
+                                        block + ", block begin: " + block.getBeginNode() + " block loop: " + block.getLoop() + ", " + blockToNodesMap.get(block).get(0));
                     }
                 }
 
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Mon Mar 23 16:11:48 2015 +0100
@@ -150,8 +150,9 @@
                 } else {
                     Block currentBlock = b;
                     assert currentBlock != null;
+
                     Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap);
-                    assert AbstractControlFlowGraph.dominates(currentBlock, latestBlock) || currentNode instanceof VirtualState : currentNode + " " + currentBlock + " " + latestBlock;
+                    assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock);
                     if (latestBlock != currentBlock) {
                         if (currentNode instanceof FloatingReadNode) {
 
@@ -200,6 +201,12 @@
         return watchListMap;
     }
 
+    private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) {
+        assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format("%s %s %s",
+                        currentNode, earliestBlock, latestBlock);
+        return true;
+    }
+
     private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
         for (Block b : cfg.getBlocks()) {
             List<Node> nodes = blockToNodesMap.get(b);
@@ -414,9 +421,11 @@
         assert currentNode.hasUsages();
         for (Node usage : currentNode.usages()) {
             block = calcBlockForUsage(currentNode, usage, block, currentNodeMap);
+            assert checkLatestEarliestRelation(currentNode, earliestBlock, block);
             if (scheduleOutOfLoops) {
-                while (block.getLoopDepth() > earliestBlock.getLoopDepth()) {
+                while (block.getLoopDepth() > earliestBlock.getLoopDepth() && block != earliestBlock.getDominator()) {
                     block = block.getDominator();
+                    assert checkLatestEarliestRelation(currentNode, earliestBlock, block);
                 }
             }
             if (block == earliestBlock) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -50,7 +50,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -36,7 +36,6 @@
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
-import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.nodes.*;
 
@@ -55,11 +54,9 @@
         installer = (ReplacementsImpl) getProviders().getReplacements();
     }
 
-    private static final ThreadLocal<SnippetInliningPolicy> inliningPolicy = new ThreadLocal<>();
-
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, inliningPolicy.get(), FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -24,14 +24,25 @@
 
 import org.junit.*;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.compiler.test.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.runtime.*;
 
 public class ReplacementsParseTest extends GraalCompilerTest {
 
+    private static final Object THROW_EXCEPTION_MARKER = new Object() {
+        @Override
+        public String toString() {
+            return "THROW_EXCEPTION_MARKER";
+        }
+    };
+
     static class TestMethods {
         static double next(double v) {
             return Math.nextAfter(v, 1.0);
@@ -45,6 +56,14 @@
             return Math.nextAfter(x, d);
         }
 
+        static String stringize(Object obj) {
+            String res = String.valueOf(obj);
+            if (res.equals(THROW_EXCEPTION_MARKER.toString())) {
+                // Tests exception throwing from partial intrinsification
+                throw new RuntimeException("ex: " + obj);
+            }
+            return res;
+        }
     }
 
     @ClassSubstitution(TestMethods.class)
@@ -55,6 +74,23 @@
             double xx = (x == -0.0 ? 0.0 : x);
             return Math.nextAfter(xx, d);
         }
+
+        @MethodSubstitution
+        static String stringize(Object obj) {
+            if (obj != null && obj.getClass() == String.class) {
+                return asNonNullString(obj);
+            } else {
+                return stringize(obj);
+            }
+        }
+
+        public static String asNonNullString(Object object) {
+            return asNonNullStringIntrinsic(object, String.class, true, true);
+        }
+
+        @NodeIntrinsic(PiNode.class)
+        private static native String asNonNullStringIntrinsic(Object object, @ConstantNodeParameter Class<?> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull);
+
     }
 
     private static boolean substitutionsInstalled;
@@ -112,4 +148,23 @@
             outArray[i] = TestMethods.nextAfter(inArray[i], direction);
         }
     }
+
+    @Test
+    public void testCallStringize() {
+        test("callStringize", "a string");
+        test("callStringize", THROW_EXCEPTION_MARKER);
+        test("callStringize", Boolean.TRUE);
+    }
+
+    public Object callStringize(Object obj) {
+        return TestMethods.stringize(obj);
+    }
+
+    @Test
+    public void testRootCompileStringize() {
+        ResolvedJavaMethod method = getResolvedJavaMethod(TestMethods.class, "stringize");
+        test(method, null, "a string");
+        test(method, null, Boolean.TRUE);
+        test(method, null, THROW_EXCEPTION_MARKER);
+    }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/StandardMethodSubstitutionsTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.replacements.test;
 
+import java.util.*;
+
 import org.junit.*;
 
 import com.oracle.graal.api.code.*;
@@ -230,6 +232,16 @@
         return clazz.isInstance(object);
     }
 
+    public static boolean isInstance2(boolean cond, Object object) {
+        Class<?> clazz;
+        if (cond) {
+            clazz = String.class;
+        } else {
+            clazz = java.util.HashMap.class;
+        }
+        return clazz.isInstance(object);
+    }
+
     public static boolean isAssignableFrom(Class<?> clazz, Class<?> other) {
         return clazz.isAssignableFrom(other);
     }
@@ -237,6 +249,7 @@
     @Test
     public void testClassSubstitutions() {
         testGraph("isInstance");
+        testGraph("isInstance2");
         testGraph("isAssignableFrom");
         for (Class<?> c : new Class[]{getClass(), Cloneable.class, int[].class, String[][].class}) {
             for (Object o : new Object[]{this, new int[5], new String[2][], new Object()}) {
@@ -244,5 +257,12 @@
                 test("isAssignableFrom", c, o.getClass());
             }
         }
+
+        test("isInstance2", true, null);
+        test("isInstance2", false, null);
+        test("isInstance2", true, "string");
+        test("isInstance2", false, "string");
+        test("isInstance2", true, new HashMap<>());
+        test("isInstance2", false, new HashMap<>());
     }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -108,32 +108,34 @@
         testGraph("unsafeDirectMemoryRead");
         testGraph("unsafeDirectMemoryWrite");
 
-        test("unsafeCompareAndSwapInt", unsafe, supply(() -> new Foo()), fooOffset("i"));
-        test("unsafeCompareAndSwapLong", unsafe, supply(() -> new Foo()), fooOffset("l"));
-        test("unsafeCompareAndSwapObject", unsafe, supply(() -> new Foo()), fooOffset("o"));
+        long address = unsafe.allocateMemory(8 * Kind.values().length);
+        for (Unsafe unsafeArg : new Unsafe[]{unsafe, null}) {
+            test("unsafeCompareAndSwapInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"));
+            test("unsafeCompareAndSwapLong", unsafeArg, supply(() -> new Foo()), fooOffset("l"));
+            test("unsafeCompareAndSwapObject", unsafeArg, supply(() -> new Foo()), fooOffset("o"));
 
-        test("unsafeGetBoolean", unsafe, supply(() -> new Foo()), fooOffset("z"));
-        test("unsafeGetByte", unsafe, supply(() -> new Foo()), fooOffset("b"));
-        test("unsafeGetShort", unsafe, supply(() -> new Foo()), fooOffset("s"));
-        test("unsafeGetChar", unsafe, supply(() -> new Foo()), fooOffset("c"));
-        test("unsafeGetInt", unsafe, supply(() -> new Foo()), fooOffset("i"));
-        test("unsafeGetLong", unsafe, supply(() -> new Foo()), fooOffset("l"));
-        test("unsafeGetFloat", unsafe, supply(() -> new Foo()), fooOffset("f"));
-        test("unsafeGetDouble", unsafe, supply(() -> new Foo()), fooOffset("d"));
-        test("unsafeGetObject", unsafe, supply(() -> new Foo()), fooOffset("o"));
+            test("unsafeGetBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z"));
+            test("unsafeGetByte", unsafeArg, supply(() -> new Foo()), fooOffset("b"));
+            test("unsafeGetShort", unsafeArg, supply(() -> new Foo()), fooOffset("s"));
+            test("unsafeGetChar", unsafeArg, supply(() -> new Foo()), fooOffset("c"));
+            test("unsafeGetInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"));
+            test("unsafeGetLong", unsafeArg, supply(() -> new Foo()), fooOffset("l"));
+            test("unsafeGetFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f"));
+            test("unsafeGetDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d"));
+            test("unsafeGetObject", unsafeArg, supply(() -> new Foo()), fooOffset("o"));
 
-        test("unsafePutBoolean", unsafe, supply(() -> new Foo()), fooOffset("z"), true);
-        test("unsafePutByte", unsafe, supply(() -> new Foo()), fooOffset("b"), (byte) 87);
-        test("unsafePutShort", unsafe, supply(() -> new Foo()), fooOffset("s"), (short) -93);
-        test("unsafePutChar", unsafe, supply(() -> new Foo()), fooOffset("c"), 'A');
-        test("unsafePutInt", unsafe, supply(() -> new Foo()), fooOffset("i"), 42);
-        test("unsafePutFloat", unsafe, supply(() -> new Foo()), fooOffset("f"), 58.0F);
-        test("unsafePutDouble", unsafe, supply(() -> new Foo()), fooOffset("d"), -28736.243465D);
-        test("unsafePutObject", unsafe, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3");
+            test("unsafePutBoolean", unsafeArg, supply(() -> new Foo()), fooOffset("z"), true);
+            test("unsafePutByte", unsafeArg, supply(() -> new Foo()), fooOffset("b"), (byte) 87);
+            test("unsafePutShort", unsafeArg, supply(() -> new Foo()), fooOffset("s"), (short) -93);
+            test("unsafePutChar", unsafeArg, supply(() -> new Foo()), fooOffset("c"), 'A');
+            test("unsafePutInt", unsafeArg, supply(() -> new Foo()), fooOffset("i"), 42);
+            test("unsafePutFloat", unsafeArg, supply(() -> new Foo()), fooOffset("f"), 58.0F);
+            test("unsafePutDouble", unsafeArg, supply(() -> new Foo()), fooOffset("d"), -28736.243465D);
+            test("unsafePutObject", unsafeArg, supply(() -> new Foo()), fooOffset("i"), "value1", "value2", "value3");
 
-        long address = unsafe.allocateMemory(8 * Kind.values().length);
-        test("unsafeDirectMemoryRead", unsafe, address);
-        test("unsafeDirectMemoryWrite", unsafe, address, 0xCAFEBABEDEADBABEL);
+            test("unsafeDirectMemoryRead", unsafeArg, address);
+            test("unsafeDirectMemoryWrite", unsafeArg, address, 0xCAFEBABEDEADBABEL);
+        }
         unsafe.freeMemory(address);
     }
 
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Mar 23 16:11:48 2015 +0100
@@ -45,7 +45,7 @@
 
     @Override
     protected StructuredGraph parseEager(ResolvedJavaMethod m, AllowAssumptions allowAssumptions) {
-        return installer.makeGraph(m, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+        return installer.makeGraph(m, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
     }
 
     @Test
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Mon Mar 23 16:11:48 2015 +0100
@@ -32,141 +32,109 @@
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
 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.nodes.util.*;
 import com.oracle.graal.phases.util.*;
-import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
 import com.oracle.graal.replacements.SnippetTemplate.AbstractTemplates;
 import com.oracle.graal.replacements.SnippetTemplate.Arguments;
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
-import com.oracle.graal.word.*;
 
 public class BoxingSnippets implements Snippets {
 
-    /**
-     * This snippet inlining policy differs from the default one in that it does normal inlining of
-     * boxing methods like {@link Integer#valueOf(int)} (as opposed to method substitution).
-     */
-    public static class BoxingSnippetInliningPolicy implements SnippetInliningPolicy {
-
-        @Override
-        public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
-            if (method.isNative()) {
-                return false;
-            }
-            if (method.getAnnotation(Fold.class) != null) {
-                return false;
-            }
-            if (method.getAnnotation(NodeIntrinsic.class) != null) {
-                return false;
-            }
-            if (method.getAnnotation(Word.Operation.class) != null) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) {
-            return false;
-        }
-    }
-
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object booleanValueOf(boolean value) {
         valueOfCounter.inc();
         return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object byteValueOf(byte value) {
         valueOfCounter.inc();
         return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object charValueOf(char value) {
         valueOfCounter.inc();
         return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object doubleValueOf(double value) {
         valueOfCounter.inc();
         return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object floatValueOf(float value) {
         valueOfCounter.inc();
         return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object intValueOf(int value) {
         valueOfCounter.inc();
         return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object longValueOf(long value) {
         valueOfCounter.inc();
         return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static Object shortValueOf(short value) {
         valueOfCounter.inc();
         return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static boolean booleanValue(Boolean value) {
         valueOfCounter.inc();
         return value.booleanValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static byte byteValue(Byte value) {
         valueOfCounter.inc();
         return value.byteValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static char charValue(Character value) {
         valueOfCounter.inc();
         return value.charValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static double doubleValue(Double value) {
         valueOfCounter.inc();
         return value.doubleValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static float floatValue(Float value) {
         valueOfCounter.inc();
         return value.floatValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static int intValue(Integer value) {
         valueOfCounter.inc();
         return value.intValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static long longValue(Long value) {
         valueOfCounter.inc();
         return value.longValue();
     }
 
-    @Snippet(inlining = BoxingSnippetInliningPolicy.class)
+    @Snippet
     public static short shortValue(Short value) {
         valueOfCounter.inc();
         return value.shortValue();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/DefaultInlineInvokePlugin.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,52 @@
+/*
+ * 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.replacements;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.nodes.*;
+
+public final class DefaultInlineInvokePlugin implements InlineInvokePlugin {
+    private final ReplacementsImpl replacements;
+
+    public DefaultInlineInvokePlugin(ReplacementsImpl replacements) {
+        this.replacements = replacements;
+    }
+
+    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        InlineInfo inlineInfo = replacements.getInlineInfo(b, method, args, returnType);
+        if (inlineInfo == null) {
+            if (InlineDuringParsing.getValue() && method.hasBytecodes() && method.getCode().length <= TrivialInliningSize.getValue() && b.getDepth() < InlineDuringParsingMaxDepth.getValue()) {
+                return new InlineInfo(method, false, false);
+            }
+        }
+        return inlineInfo;
+    }
+
+    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        replacements.notifyOfNoninlinedInvoke(b, method, invoke);
+    }
+}
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon Mar 23 16:11:48 2015 +0100
@@ -28,16 +28,21 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.CallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.StructuredGraph.AllowAssumptions;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.util.*;
-import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
 import com.oracle.graal.word.*;
 
 /**
@@ -50,6 +55,7 @@
     protected final Providers providers;
     protected final StructuredGraph graph;
     protected final WordTypes wordTypes;
+    protected final GraphBuilderConfiguration.Plugins graphBuilderPlugins;
     protected FixedWithNextNode lastFixedNode;
 
     private final List<Structure> structures;
@@ -57,10 +63,11 @@
     abstract static class Structure {
     }
 
-    public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes) {
+    public GraphKit(StructuredGraph graph, Providers providers, WordTypes wordTypes, GraphBuilderConfiguration.Plugins graphBuilderPlugins) {
         this.providers = providers;
         this.graph = graph;
         this.wordTypes = wordTypes;
+        this.graphBuilderPlugins = graphBuilderPlugins;
         this.lastFixedNode = graph.start();
 
         structures = new ArrayList<>();
@@ -202,14 +209,28 @@
     }
 
     /**
-     * Inlines a given invocation to a method. The graph of the inlined method is
-     * {@linkplain ReplacementsImpl#makeGraph processed} in the same manner as for snippets and
-     * method substitutions.
+     * Inlines a given invocation to a method. The graph of the inlined method is processed in the
+     * same manner as for snippets and method substitutions.
      */
     public void inline(InvokeNode invoke) {
         ResolvedJavaMethod method = ((MethodCallTargetNode) invoke.callTarget()).targetMethod();
-        ReplacementsImpl replacements = (ReplacementsImpl) providers.getReplacements();
-        StructuredGraph calleeGraph = replacements.makeGraph(method, null, null, null, FrameStateProcessing.CollapseFrameForSingleSideEffect);
+
+        MetaAccessProvider metaAccess = providers.getMetaAccess();
+        Plugins plugins = new Plugins(graphBuilderPlugins);
+        GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
+
+        StructuredGraph calleeGraph = new StructuredGraph(method, AllowAssumptions.NO);
+        IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, null, IntrinsicContext.POST_PARSE_INLINE_BCI);
+        new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), config, OptimisticOptimizations.NONE, initialReplacementContext).apply(calleeGraph);
+
+        // Remove all frame states from inlinee
+        for (Node node : calleeGraph.getNodes()) {
+            if (node instanceof StateSplit) {
+                ((StateSplit) node).setStateAfter(null);
+            }
+        }
+        new DeadCodeEliminationPhase(Optionality.Required).apply(calleeGraph);
+
         InliningUtil.inline(invoke, calleeGraph, false, null);
     }
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Mar 23 16:11:48 2015 +0100
@@ -25,7 +25,9 @@
 import static com.oracle.graal.api.meta.MetaUtil.*;
 import static com.oracle.graal.compiler.GraalCompiler.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.java.AbstractBytecodeParser.Options.*;
 import static com.oracle.graal.phases.common.DeadCodeEliminationPhase.Optionality.*;
+import static java.lang.String.*;
 
 import java.lang.reflect.*;
 import java.util.*;
@@ -41,10 +43,14 @@
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
-import com.oracle.graal.graph.*;
+import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
+import com.oracle.graal.graphbuilderconf.InlineInvokePlugin.InlineInfo;
+import com.oracle.graal.java.AbstractBytecodeParser.IntrinsicContext;
+import com.oracle.graal.java.AbstractBytecodeParser.ReplacementContext;
 import com.oracle.graal.java.*;
 import com.oracle.graal.java.GraphBuilderPhase.Instance;
 import com.oracle.graal.nodes.*;
@@ -53,13 +59,11 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
-import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy;
-import com.oracle.graal.replacements.Snippet.SnippetInliningPolicy;
+import com.oracle.graal.word.*;
 
-public class ReplacementsImpl implements Replacements {
+public class ReplacementsImpl implements Replacements, InlineInvokePlugin {
 
     public final Providers providers;
     public final SnippetReflectionProvider snippetReflection;
@@ -77,6 +81,56 @@
         this.graphBuilderPlugins = plugins;
     }
 
+    protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
+        return nodeIntrinsificationPhase.getIntrinsic(method) != null || method.getAnnotation(Word.Operation.class) != null || nodeIntrinsificationPhase.isFoldable(method);
+    }
+
+    private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
+
+    /**
+     * Determines whether a given method should be inlined based on whether it has a substitution or
+     * whether the inlining context is already within a substitution.
+     *
+     * @return an {@link InlineInfo} object specifying how {@code method} is to be inlined or null
+     *         if it should not be inlined based on substitution related criteria
+     */
+    public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
+        ResolvedJavaMethod subst = getMethodSubstitutionMethod(method);
+        if (subst != null) {
+            if (b.parsingReplacement() || InlineDuringParsing.getValue()) {
+                // Forced inlining of intrinsics
+                return new InlineInfo(subst, true, true);
+            }
+            return null;
+        }
+        if (b.parsingReplacement()) {
+            assert !hasGenericInvocationPluginAnnotation(method) : format("%s should have been handled by %s", method.format("%H.%n(%p)"), DefaultGenericInvocationPlugin.class.getName());
+
+            assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
+
+            if (method.getName().startsWith("$jacoco")) {
+                throw new GraalInternalError("Found call to JaCoCo instrumentation method " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " +
+                                b.getMethod().getDeclaringClass().getSourceFileName() + " should fix this.");
+            }
+
+            // Force inlining when parsing replacements
+            return new InlineInfo(method, true, true);
+        } else {
+            assert nodeIntrinsificationPhase.getIntrinsic(method) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
+                            method.format("%h.%n"), b);
+        }
+        return null;
+    }
+
+    public void notifyOfNoninlinedInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
+        if (b.parsingReplacement()) {
+            boolean compilingSnippet = b.getRootMethod().getAnnotation(Snippet.class) != null;
+            Replacement replacement = b.getReplacement();
+            assert compilingSnippet : format("All calls in the replacement %s must be inlined or intrinsified: found call to %s", replacement.getReplacementMethod().format("%H.%n(%p)"),
+                            method.format("%h.%n(%p)"));
+        }
+    }
+
     /**
      * Encapsulates method and macro substitutions for a single class.
      */
@@ -273,7 +327,7 @@
             try (DebugCloseable a = SnippetPreparationTime.start()) {
                 FrameStateProcessing frameStateProcessing = method.getAnnotation(Snippet.class).removeAllFrameStates() ? FrameStateProcessing.Removal
                                 : FrameStateProcessing.CollapseFrameForSingleSideEffect;
-                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, inliningPolicy(method), frameStateProcessing);
+                StructuredGraph newGraph = makeGraph(method, args, recursiveEntry, frameStateProcessing);
                 Debug.metric("SnippetNodeCount[%#s]", method).add(newGraph.getNodeCount());
                 if (!UseSnippetGraphCache || args != null) {
                     return newGraph;
@@ -313,7 +367,7 @@
         }
         StructuredGraph graph = graphs.get(substitute);
         if (graph == null) {
-            graph = makeGraph(substitute, null, original, inliningPolicy(substitute), FrameStateProcessing.None);
+            graph = makeGraph(substitute, null, original, FrameStateProcessing.None);
             graph.freeze();
             graphs.putIfAbsent(substitute, graph);
             graph = graphs.get(substitute);
@@ -424,26 +478,6 @@
         return originalJavaMethod;
     }
 
-    private static SnippetInliningPolicy createPolicyClassInstance(Class<? extends SnippetInliningPolicy> policyClass) {
-        try {
-            return policyClass.getConstructor().newInstance();
-        } catch (Exception e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
-    public SnippetInliningPolicy inliningPolicy(ResolvedJavaMethod method) {
-        Class<? extends SnippetInliningPolicy> policyClass = SnippetInliningPolicy.class;
-        Snippet snippet = method.getAnnotation(Snippet.class);
-        if (snippet != null) {
-            policyClass = snippet.inlining();
-        }
-        if (policyClass == SnippetInliningPolicy.class) {
-            return new DefaultSnippetInliningPolicy(providers.getMetaAccess());
-        }
-        return createPolicyClassInstance(policyClass);
-    }
-
     /**
      * Creates a preprocessed graph for a snippet or method substitution.
      *
@@ -451,11 +485,10 @@
      * @param args
      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
      *            substitution} otherwise null
-     * @param policy the inlining policy to use during preprocessing
      * @param frameStateProcessing controls how {@link FrameState FrameStates} should be handled.
      */
-    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, SnippetInliningPolicy policy, FrameStateProcessing frameStateProcessing) {
-        return createGraphMaker(method, original, frameStateProcessing).makeGraph(args, policy);
+    public StructuredGraph makeGraph(ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, FrameStateProcessing frameStateProcessing) {
+        return createGraphMaker(method, original, frameStateProcessing).makeGraph(args);
     }
 
     /**
@@ -527,9 +560,9 @@
             this.frameStateProcessing = frameStateProcessing;
         }
 
-        public StructuredGraph makeGraph(Object[] args, final SnippetInliningPolicy policy) {
+        public StructuredGraph makeGraph(Object[] args) {
             try (Scope s = Debug.scope("BuildSnippetGraph", method)) {
-                StructuredGraph graph = parseGraph(method, args, policy, 0);
+                StructuredGraph graph = parseGraph(method, args);
 
                 if (args == null) {
                     // Cannot have a finalized version of a graph in the cache
@@ -603,14 +636,12 @@
             return false;
         }
 
-        private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
-
-        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) {
+        private StructuredGraph parseGraph(final ResolvedJavaMethod methodToParse, Object[] args) {
             StructuredGraph graph = args == null ? replacements.graphCache.get(methodToParse) : null;
             if (graph == null) {
                 StructuredGraph newGraph = null;
                 try (Scope s = Debug.scope("ParseGraph", methodToParse)) {
-                    newGraph = buildGraph(methodToParse, args, policy == null ? replacements.inliningPolicy(methodToParse) : policy, inliningDepth);
+                    newGraph = buildGraph(methodToParse, args);
                 } catch (Throwable e) {
                     throw Debug.handle(e);
                 }
@@ -662,8 +693,17 @@
 
         protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, GraphBuilderConfiguration graphBuilderConfig,
                         OptimisticOptimizations optimisticOpts) {
-            ResolvedJavaMethod rootMethodIsReplacement = substitutedMethod == null ? method : substitutedMethod;
-            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, rootMethodIsReplacement);
+            ReplacementContext initialReplacementContext = null;
+            if (method.getAnnotation(MethodSubstitution.class) != null) {
+                // Late inlined intrinsic
+                initialReplacementContext = new IntrinsicContext(substitutedMethod, method, null, -1);
+            } else {
+                // Snippet
+                assert method.getAnnotation(Snippet.class) != null;
+                ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
+                initialReplacementContext = new ReplacementContext(original, method);
+            }
+            return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, graphBuilderConfig, optimisticOpts, initialReplacementContext);
         }
 
         /**
@@ -700,67 +740,10 @@
             }
         }
 
-        private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args, final SnippetInliningPolicy policy, int inliningDepth) {
-            assert inliningDepth < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
+        private StructuredGraph buildGraph(final ResolvedJavaMethod methodToParse, Object[] args) {
             assert methodToParse.hasBytecodes() : methodToParse;
             final StructuredGraph graph = buildInitialGraph(methodToParse, args);
             try (Scope s = Debug.scope("buildGraph", graph)) {
-                Set<MethodCallTargetNode> doNotInline = null;
-                for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) {
-                    if (doNotInline != null && doNotInline.contains(callTarget)) {
-                        continue;
-                    }
-                    ResolvedJavaMethod callee = callTarget.targetMethod();
-                    if (substitutedMethod != null && (callee.equals(method) || callee.equals(substitutedMethod))) {
-                        /*
-                         * Ensure that calls to the original method inside of a substitution ends up
-                         * calling it instead of the Graal substitution.
-                         */
-                        if (substitutedMethod.hasBytecodes()) {
-                            final StructuredGraph originalGraph = buildInitialGraph(substitutedMethod, null);
-                            Mark mark = graph.getMark();
-                            InliningUtil.inline(callTarget.invoke(), originalGraph, true, null);
-                            for (MethodCallTargetNode inlinedCallTarget : graph.getNewNodes(mark).filter(MethodCallTargetNode.class)) {
-                                if (doNotInline == null) {
-                                    doNotInline = new HashSet<>();
-                                }
-                                // We do not want to do further inlining (now) for calls
-                                // in the original method as this can cause unlimited
-                                // recursive inlining given an eager inlining policy such
-                                // as DefaultSnippetInliningPolicy.
-                                doNotInline.add(inlinedCallTarget);
-                            }
-                            Debug.dump(graph, "after inlining %s", callee);
-                            afterInline(graph, originalGraph, null);
-                        }
-                    } else {
-                        Class<? extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(replacements, callee);
-                        if (macroNodeClass != null) {
-                            InliningUtil.inlineMacroNode(callTarget.invoke(), callee, macroNodeClass);
-                        } else {
-                            StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(replacements, callee);
-                            if (callTarget.invokeKind().isDirect() && (policy.shouldInline(callee, methodToParse) || (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)))) {
-                                StructuredGraph targetGraph;
-                                if (intrinsicGraph != null && policy.shouldUseReplacement(callee, methodToParse)) {
-                                    targetGraph = intrinsicGraph;
-                                } else {
-                                    if (callee.getName().startsWith("$jacoco")) {
-                                        throw new GraalInternalError("Parsing call to JaCoCo instrumentation method " + callee.format("%H.%n(%p)") + " from " + methodToParse.format("%H.%n(%p)") +
-                                                        " while preparing replacement " + method.format("%H.%n(%p)") + ". Placing \"//JaCoCo Exclude\" anywhere in " +
-                                                        methodToParse.getDeclaringClass().getSourceFileName() + " should fix this.");
-                                    }
-                                    targetGraph = parseGraph(callee, null, policy, inliningDepth + 1);
-                                }
-                                Object beforeInlineData = beforeInline(callTarget, targetGraph);
-                                InliningUtil.inline(callTarget.invoke(), targetGraph, true, null);
-                                Debug.dump(graph, "after inlining %s", callee);
-                                afterInline(graph, targetGraph, beforeInlineData);
-                            }
-                        }
-                    }
-                }
-
-                afterInlining(graph);
 
                 for (LoopEndNode end : graph.getNodes(LoopEndNode.TYPE)) {
                     end.disableSafepoint();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Mon Mar 23 16:11:48 2015 +0100
@@ -24,11 +24,7 @@
 
 import java.lang.annotation.*;
 
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.replacements.nodes.*;
-import com.oracle.graal.word.*;
 
 /**
  * A snippet is a Graal graph expressed as a Java source method. Snippets are used for lowering
@@ -39,12 +35,6 @@
 public @interface Snippet {
 
     /**
-     * Specifies the class defining the inlining policy for this snippet. A
-     * {@linkplain DefaultSnippetInliningPolicy default} policy is used if none is supplied.
-     */
-    Class<? extends SnippetInliningPolicy> inlining() default SnippetInliningPolicy.class;
-
-    /**
      * Specifies whether all FrameStates within this snippet should always be removed. If this is
      * false, FrameStates are only removed if there are no side-effecting instructions in the
      * snippet.
@@ -52,70 +42,6 @@
     boolean removeAllFrameStates() default false;
 
     /**
-     * Guides inlining decisions used when installing a snippet.
-     */
-    public interface SnippetInliningPolicy {
-
-        /**
-         * Determines if {@code method} should be inlined into {@code caller}.
-         */
-        boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller);
-
-        /**
-         * Determines if {@code method} should be inlined using its replacement graph.
-         *
-         * @return true if the replacement graph should be used, false for normal inlining.
-         */
-        boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse);
-    }
-
-    /**
-     * The default inlining policy which inlines everything except for methods in any of the
-     * following categories.
-     * <ul>
-     * <li>{@linkplain Fold foldable} methods</li>
-     * <li>{@linkplain NodeIntrinsic node intrinsics}</li>
-     * <li>native methods</li>
-     * <li>constructors of {@link Throwable} classes</li>
-     * </ul>
-     */
-    public static class DefaultSnippetInliningPolicy implements SnippetInliningPolicy {
-
-        private final MetaAccessProvider metaAccess;
-
-        public DefaultSnippetInliningPolicy(MetaAccessProvider metaAccess) {
-            this.metaAccess = metaAccess;
-        }
-
-        @Override
-        public boolean shouldInline(ResolvedJavaMethod method, ResolvedJavaMethod caller) {
-            if (method.isNative()) {
-                return false;
-            }
-            if (method.getAnnotation(Fold.class) != null) {
-                return false;
-            }
-            if (method.getAnnotation(NodeIntrinsic.class) != null) {
-                return false;
-            }
-            if (metaAccess.lookupJavaType(Throwable.class).isAssignableFrom(method.getDeclaringClass())) {
-                if (method.isConstructor()) {
-                    return false;
-                }
-            }
-            if (method.getAnnotation(Word.Operation.class) != null) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public boolean shouldUseReplacement(ResolvedJavaMethod callee, ResolvedJavaMethod methodToParse) {
-            return true;
-        }
-    }
-
-    /**
      * Denotes a snippet parameter representing 0 or more arguments that will be bound during
      * snippet template {@linkplain SnippetTemplate#instantiate instantiation}. During snippet
      * template creation, its value must be an array whose length specifies the number of arguments
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java	Mon Mar 23 16:11:48 2015 +0100
@@ -158,7 +158,7 @@
 
         void notifyNewTemplate() {
             templateCount++;
-            if (UseSnippetTemplateCache && templateCount > MaxTemplatesPerSnippet) {
+            if (UseSnippetTemplateCache && templateCount == MaxTemplatesPerSnippet) {
                 PrintStream err = System.err;
                 err.printf("WARNING: Exceeded %d templates for snippet %s%n" + "         Adjust maximum with %s system property%n", MaxTemplatesPerSnippet, method.format("%h.%n(%p)"),
                                 MAX_TEMPLATES_PER_SNIPPET_PROPERTY_NAME);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Mon Mar 23 16:11:48 2015 +0100
@@ -23,7 +23,6 @@
 package com.oracle.graal.replacements;
 
 import static com.oracle.graal.api.code.MemoryBarriers.*;
-import static com.oracle.graal.graphbuilderconf.GraphBuilderContext.*;
 import static com.oracle.graal.replacements.nodes.MathIntrinsicNode.Operation.*;
 import sun.misc.*;
 
@@ -33,7 +32,8 @@
 import com.oracle.graal.compiler.common.calc.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.debug.*;
@@ -105,7 +105,9 @@
         for (Kind kind : new Kind[]{Kind.Int, Kind.Long, Kind.Object}) {
             Class<?> javaClass = kind == Kind.Object ? Object.class : kind.toJavaClass();
             r.register5("compareAndSwap" + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
+                    // Emits a null-check for the otherwise unused receiver
+                    unsafe.get();
                     CompareAndSwapNode compareAndSwap = new CompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any());
                     b.push(Kind.Boolean.getStackKind(), b.append(compareAndSwap));
                     compareAndSwap.setStateAfter(b.createStateAfter());
@@ -115,7 +117,9 @@
 
             if (getAndSetEnabled(arch)) {
                 r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
-                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
+                        // Emits a null-check for the otherwise unused receiver
+                        unsafe.get();
                         AtomicReadAndWriteNode atomicReadWrite = new AtomicReadAndWriteNode(object, offset, value, kind, LocationIdentity.any());
                         b.push(kind.getStackKind(), b.append(atomicReadWrite));
                         atomicReadWrite.setStateAfter(b.createStateAfter());
@@ -124,7 +128,9 @@
                 });
                 if (kind != Kind.Object) {
                     r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
-                        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode delta) {
+                        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
+                            // Emits a null-check for the otherwise unused receiver
+                            unsafe.get();
                             AtomicReadAndAddNode atomicReadAdd = new AtomicReadAndAddNode(object, offset, delta, LocationIdentity.any());
                             b.push(kind.getStackKind(), b.append(atomicReadAdd));
                             atomicReadAdd.setStateAfter(b.createStateAfter());
@@ -150,26 +156,26 @@
         Class<?> type = kind.toJavaClass();
         Registration r = new Registration(plugins, declaringClass);
         r.register1("reverseBytes", type, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(kind, b.append(new ReverseBytesNode(value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("bitCount", type, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Int, b.append(new BitCountNode(value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register2("divideUnsigned", type, type, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) {
-                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
+                b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
                 return true;
             }
         });
         r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) {
-                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
+                b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
                 return true;
             }
         });
@@ -178,12 +184,12 @@
     private static void registerCharacterPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Character.class);
         r.register1("reverseBytes", char.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 // return (char) (Integer.reverse(i) >> 16);
                 ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
                 ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
-                b.push(Kind.Char.getStackKind(), b.append(charCast.canonical(null, value)));
+                b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
         });
@@ -192,12 +198,12 @@
     private static void registerShortPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Short.class);
         r.register1("reverseBytes", short.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 // return (short) (Integer.reverse(i) >> 16);
                 ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
                 SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
-                b.push(Kind.Short.getStackKind(), b.append(charCast.canonical(null, value)));
+                b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
         });
@@ -206,14 +212,14 @@
     private static void registerFloatPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Float.class);
         r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Int, b.append(new ReinterpretNode(Kind.Int, value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Int, b.recursiveAppend(new ReinterpretNode(Kind.Int, value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Float, b.append(new ReinterpretNode(Kind.Float, value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Float, b.recursiveAppend(new ReinterpretNode(Kind.Float, value).canonical(null, value)));
                 return true;
             }
         });
@@ -222,14 +228,14 @@
     private static void registerDoublePlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Double.class);
         r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Long, b.append(new ReinterpretNode(Kind.Long, value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Long, b.recursiveAppend(new ReinterpretNode(Kind.Long, value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Double, b.append(new ReinterpretNode(Kind.Double, value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Double, b.recursiveAppend(new ReinterpretNode(Kind.Double, value).canonical(null, value)));
                 return true;
             }
         });
@@ -238,33 +244,33 @@
     private static void registerMathPlugins(Architecture arch, InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Math.class);
         r.register1("abs", Float.TYPE, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Float, b.append(new AbsNode(value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Float, b.recursiveAppend(new AbsNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("abs", Double.TYPE, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Double, b.append(new AbsNode(value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Double, b.recursiveAppend(new AbsNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Double, b.append(new SqrtNode(value).canonical(null, value)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                b.push(Kind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null, value)));
                 return true;
             }
         });
         if (getAndSetEnabled(arch)) {
             r.register1("log", Double.TYPE, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                    b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG)));
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                    b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG)));
                     return true;
                 }
             });
             r.register1("log10", Double.TYPE, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                    b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG10)));
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+                    b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG10)));
                     return true;
                 }
             });
@@ -278,7 +284,7 @@
             this.condition = condition;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
             // the mirroring and negation operations get the condition into canonical form
             boolean mirror = condition.canonicalMirror();
             boolean negate = condition.canonicalNegate();
@@ -312,26 +318,26 @@
         r.register2("belowOrEqual", int.class, int.class, new UnsignedMathPlugin(Condition.BE));
         r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE));
         r.register2("divide", int.class, int.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Int, b.append(new UnsignedDivNode(x, y).canonical(null, x, y)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                b.push(Kind.Int, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
         r.register2("divide", long.class, long.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Long, b.append(new UnsignedDivNode(x, y).canonical(null, x, y)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                b.push(Kind.Long, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
         r.register2("remainder", int.class, int.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Int, b.append(new UnsignedRemNode(x, y).canonical(null, x, y)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                b.push(Kind.Int, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
         r.register2("remainder", long.class, long.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Long, b.append(new UnsignedRemNode(x, y).canonical(null, x, y)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
+                b.push(Kind.Long, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
@@ -349,7 +355,8 @@
     private static void registerObjectPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Object.class);
         r.register1("<init>", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                ValueNode object = receiver.get();
                 if (RegisterFinalizerNode.mayHaveFinalizer(object, b.getAssumptions())) {
                     RegisterFinalizerNode registerFinalizer = new RegisterFinalizerNode(object);
                     b.append(registerFinalizer);
@@ -363,24 +370,23 @@
     private static void registerClassPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Class.class);
         r.register2("isInstance", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) {
-                ValueNode nullCheckedType = nullCheckedValue(b, type);
-                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object));
-                b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode object) {
+                LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), type.get(), object));
+                b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
         r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode otherType) {
-                ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType));
-                b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver type, ValueNode otherType) {
+                ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(type.get(), otherType));
+                b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
         r.register2("cast", Receiver.class, Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr, ValueNode object) {
-                if (rcvr.isConstant() && !rcvr.isNullConstant()) {
-                    ResolvedJavaType type = b.getConstantReflection().asJavaType(rcvr.asConstant());
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object) {
+                if (receiver.isConstant()) {
+                    ResolvedJavaType type = b.getConstantReflection().asJavaType(receiver.get().asConstant());
                     if (type != null && !type.isPrimitive()) {
                         b.push(Kind.Object, b.append(CheckCastNode.create(type, object, null, false, b.getAssumptions())));
                         return true;
@@ -402,7 +408,7 @@
         Registration r = new Registration(plugins, Edges.class);
         for (Class<?> c : new Class<?>[]{Node.class, NodeList.class}) {
             r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) {
                     ValueNode value = b.append(new UnsafeLoadNode(node, offset, Kind.Object, LocationIdentity.any()));
                     boolean exactType = false;
                     boolean nonNull = false;
@@ -411,7 +417,7 @@
                 }
             });
             r.register3("put" + c.getSimpleName() + "Unsafe", Node.class, long.class, c, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode node, ValueNode offset, ValueNode value) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset, ValueNode value) {
                     UnsafeStoreNode unsafeStore = new UnsafeStoreNode(node, offset, value, Kind.Object, LocationIdentity.any());
                     b.append(unsafeStore);
                     unsafeStore.setStateAfter(b.createStateAfter());
@@ -429,7 +435,7 @@
             this.kind = kind;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
             if (b.parsingReplacement()) {
                 ResolvedJavaMethod rootMethod = b.getRootMethod();
                 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
@@ -456,7 +462,7 @@
             this.kind = kind;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
             if (b.parsingReplacement()) {
                 ResolvedJavaMethod rootMethod = b.getRootMethod();
                 if (b.getMetaAccess().lookupJavaType(BoxingSnippets.class).isAssignableFrom(rootMethod.getDeclaringClass())) {
@@ -465,7 +471,7 @@
                     return false;
                 }
             }
-            ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), nullCheckedValue(b, value), kind);
+            ValueNode valueNode = UnboxNode.create(b.getMetaAccess(), b.getConstantReflection(), receiver.get(), kind);
             b.push(kind.getStackKind(), b.append(valueNode));
             return true;
         }
@@ -486,12 +492,16 @@
             this.isVolatile = isVolatile;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
             b.push(returnKind.getStackKind(), b.append(new DirectReadNode(address, returnKind)));
             return true;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
             if (isVolatile) {
                 b.append(new MembarNode(JMM_PRE_VOLATILE_READ));
             }
@@ -513,12 +523,16 @@
             this.isVolatile = isVolatile;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode address, ValueNode value) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode address, ValueNode value) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
             b.append(new DirectStoreNode(address, value, kind));
             return true;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode ignoredUnsafe, ValueNode object, ValueNode offset, ValueNode value) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode value) {
+            // Emits a null-check for the otherwise unused receiver
+            unsafe.get();
             if (isVolatile) {
                 b.append(new MembarNode(JMM_PRE_VOLATILE_WRITE));
             }
@@ -535,42 +549,42 @@
     private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, GraalDirectives.class);
         r.register0("deoptimize", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
 
         r.register0("deoptimizeAndInvalidate", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
 
         r.register0("inCompiledCode", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.push(Kind.Int, b.append(ConstantNode.forInt(1)));
                 return true;
             }
         });
 
         r.register0("controlFlowAnchor", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.append(new ControlFlowAnchorNode());
                 return true;
             }
         });
 
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
                 b.push(Kind.Int, b.append(new BranchProbabilityNode(probability, condition)));
                 return true;
             }
         });
 
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 b.append(new BlackholeNode(value));
                 return true;
             }
@@ -583,7 +597,7 @@
 
                 final Kind stackKind = kind.getStackKind();
                 r.register1("opaque", javaClass, new InvocationPlugin() {
-                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+                    public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                         b.push(stackKind, b.append(new OpaqueNode(value)));
                         return true;
                     }
@@ -594,7 +608,8 @@
 
     private static void registerJMHBlackholePlugins(InvocationPlugins plugins) {
         InvocationPlugin blackholePlugin = new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode blackhole, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver blackhole, ValueNode value) {
+                blackhole.get();
                 b.append(new BlackholeNode(value));
                 return true;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultLoopNodeFactory.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import com.oracle.graal.api.runtime.*;
+import com.oracle.truffle.api.nodes.*;
+
+@ServiceProvider(LoopNodeFactory.class)
+public class DefaultLoopNodeFactory implements LoopNodeFactory {
+
+    public LoopNode create(RepeatingNode repeatingNode) {
+        return new OptimizedLoopNode(repeatingNode);
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategy.java	Mon Mar 23 16:11:48 2015 +0100
@@ -62,7 +62,7 @@
             return false;
         }
         OptimizedCallTarget splitTarget = call.getCallTarget();
-        int nodeCount = splitTarget.countNonTrivialNodes();
+        int nodeCount = splitTarget.getNonTrivialNodeCount();
         if (nodeCount > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) {
             return false;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/DefaultTruffleSplittingStrategyNew.java	Mon Mar 23 16:11:48 2015 +0100
@@ -55,7 +55,7 @@
         if (TruffleCompilerOptions.TruffleSplittingAggressive.getValue()) {
             return true;
         }
-        int size = call.getCallTarget().countNonTrivialNodes();
+        int size = call.getCallTarget().getNonTrivialNodeCount();
         if (size > TruffleCompilerOptions.TruffleSplittingMaxCalleeSize.getValue()) {
             return false;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/GraalTruffleRuntime.java	Mon Mar 23 16:11:48 2015 +0100
@@ -56,10 +56,28 @@
     private final List<GraalTruffleCompilationListener> compilationListeners = new ArrayList<>();
     private final GraalTruffleCompilationListener compilationNotify = new DispatchTruffleCompilationListener();
 
+    private LoopNodeFactory loopNodeFactory;
+
     public GraalTruffleRuntime() {
         Runtime.getRuntime().addShutdownHook(new Thread(this::shutdown));
     }
 
+    private static <T extends PrioritizedServiceProvider> T loadPrioritizedServiceProvider(Class<T> clazz) {
+        ServiceLoader<T> serviceLoader = ServiceLoader.load(clazz, GraalTruffleRuntime.class.getClassLoader());
+        T bestFactory = null;
+        for (T factory : serviceLoader) {
+            if (bestFactory == null) {
+                bestFactory = factory;
+            } else if (factory.getPriority() > bestFactory.getPriority()) {
+                bestFactory = factory;
+            }
+        }
+        if (bestFactory == null) {
+            throw new IllegalStateException("Unable to load a factory for " + clazz.getName());
+        }
+        return bestFactory;
+    }
+
     protected void installDefaultListeners() {
         TraceCompilationFailureListener.install(this);
         TraceCompilationListener.install(this);
@@ -80,11 +98,15 @@
     }
 
     @Override
-    public LoopNode createLoopNode(RepeatingNode repeating) {
-        if (!(repeating instanceof Node)) {
+    public LoopNode createLoopNode(RepeatingNode repeatingNode) {
+        if (!(repeatingNode instanceof Node)) {
             throw new IllegalArgumentException("Repeating node must be of type Node.");
         }
-        return new OptimizedLoopNode(repeating);
+        if (loopNodeFactory == null) {
+            loopNodeFactory = loadPrioritizedServiceProvider(LoopNodeFactory.class);
+        }
+
+        return loopNodeFactory.create(repeatingNode);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/LoopNodeFactory.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+import com.oracle.truffle.api.nodes.*;
+
+public interface LoopNodeFactory extends PrioritizedServiceProvider {
+
+    LoopNode create(RepeatingNode repeatingNode);
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedCallTarget.java	Mon Mar 23 16:11:48 2015 +0100
@@ -486,16 +486,16 @@
         return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
     }
 
-    public final int countNonTrivialNodes() {
+    public final int getNonTrivialNodeCount() {
         if (cachedNonTrivialNodeCount == -1) {
-            cachedNonTrivialNodeCount = calculateNonTrivialNodesImpl();
+            cachedNonTrivialNodeCount = calculateNonTrivialNodes(getRootNode());
         }
         return cachedNonTrivialNodeCount;
     }
 
-    private int calculateNonTrivialNodesImpl() {
+    public static int calculateNonTrivialNodes(Node node) {
         NonTrivialNodeCountVisitor visitor = new NonTrivialNodeCountVisitor();
-        getRootNode().accept(visitor);
+        node.accept(visitor);
         return visitor.nodeCount;
     }
 
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/OptimizedLoopNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -32,15 +32,22 @@
  */
 public final class OptimizedLoopNode extends LoopNode {
 
-    public OptimizedLoopNode(RepeatingNode body) {
-        super(body);
+    @Child private RepeatingNode repeatingNode;
+
+    public OptimizedLoopNode(RepeatingNode repeatingNode) {
+        this.repeatingNode = repeatingNode;
+    }
+
+    @Override
+    public RepeatingNode getRepeatingNode() {
+        return repeatingNode;
     }
 
     @Override
     public void executeLoop(VirtualFrame frame) {
         int loopCount = 0;
         try {
-            while (executeRepeatingNode(frame)) {
+            while (repeatingNode.executeRepeating(frame)) {
                 if (CompilerDirectives.inInterpreter()) {
                     loopCount++;
                 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PrioritizedServiceProvider.java	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.truffle;
+
+public interface PrioritizedServiceProvider {
+
+    default int getPriority() {
+        return 0;
+    }
+
+}
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleInlining.java	Mon Mar 23 16:11:48 2015 +0100
@@ -43,7 +43,7 @@
     }
 
     private static List<TruffleInliningDecision> createDecisions(OptimizedCallTarget sourceTarget, TruffleInliningPolicy policy, CompilerOptions options) {
-        int nodeCount = sourceTarget.countNonTrivialNodes();
+        int nodeCount = sourceTarget.getNonTrivialNodeCount();
         List<TruffleInliningDecision> exploredCallSites = exploreCallSites(new ArrayList<>(Arrays.asList(sourceTarget)), nodeCount, policy);
         return decideInlining(exploredCallSites, policy, nodeCount, options);
     }
@@ -66,7 +66,7 @@
 
         List<TruffleInliningDecision> childCallSites = Collections.emptyList();
         double frequency = calculateFrequency(parentTarget, callNode);
-        int nodeCount = callNode.getCurrentCallTarget().countNonTrivialNodes();
+        int nodeCount = callNode.getCurrentCallTarget().getNonTrivialNodeCount();
 
         int recursions = countRecursions(callStack);
         int deepNodeCount = nodeCount;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/AbstractDebugCompilationListener.java	Mon Mar 23 16:11:48 2015 +0100
@@ -101,7 +101,7 @@
     }
 
     public static void addASTSizeProperty(OptimizedCallTarget target, Map<String, Object> properties) {
-        int nodeCount = target.countNonTrivialNodes();
+        int nodeCount = target.getNonTrivialNodeCount();
         int deepNodeCount = nodeCount;
         TruffleInlining inlining = target.getInlining();
         if (inlining != null) {
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/debug/HistogramInlineInvokePlugin.java	Mon Mar 23 16:11:48 2015 +0100
@@ -26,9 +26,11 @@
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.graphbuilderconf.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.virtual.*;
 import com.oracle.graal.truffle.*;
 
 public class HistogramInlineInvokePlugin implements InlineInvokePlugin {
@@ -47,7 +49,7 @@
     public InlineInfo getInlineInfo(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args, JavaType returnType) {
         InlineInfo inlineInfo = delegate.getInlineInfo(b, method, args, returnType);
         if (inlineInfo != null) {
-            currentStatistic = new MethodStatistic(currentStatistic, inlineInfo.methodToInline, graph.getNodeCount(), graph.getNodes(MethodCallTargetNode.TYPE).count());
+            currentStatistic = new MethodStatistic(currentStatistic, inlineInfo.methodToInline, countNodes(), countCalls());
         }
         return inlineInfo;
     }
@@ -56,13 +58,25 @@
         delegate.postInline(inlinedTargetMethod);
 
         if (currentStatistic != null) {
-            currentStatistic.applyNodeCountAfter(graph.getNodeCount());
-            currentStatistic.applyCallsAfter(graph.getNodes(MethodCallTargetNode.TYPE).count());
+            currentStatistic.applyNodeCountAfter(countNodes());
+            currentStatistic.applyCallsAfter(countCalls());
             accept(currentStatistic);
             currentStatistic = currentStatistic.getParent();
         }
     }
 
+    private int countNodes() {
+        return graph.getNodes().filter(node -> isNonTrivial(node)).count();
+    }
+
+    private int countCalls() {
+        return graph.getNodes(MethodCallTargetNode.TYPE).count();
+    }
+
+    private static boolean isNonTrivial(Node node) {
+        return !(node instanceof VirtualState || node instanceof VirtualObjectNode || node instanceof BeginNode || node instanceof DeoptimizeNode);
+    }
+
     private void accept(MethodStatistic current) {
         ResolvedJavaMethod method = current.getMethod();
         HistogramInlineInvokePlugin.MethodStatistics statistics = histogram.get(method);
@@ -74,12 +88,12 @@
     }
 
     public void print(OptimizedCallTarget target, PrintStream out) {
-        out.printf("Truffle expansion histogram for %s", target);
+        out.printf("Truffle expansion histogram for %s%n", target);
         out.println("  Invocations = Number of expanded invocations");
-        out.println("  Nodes = Number of Graal nodes created for this method during partial evaluation.");
+        out.println("  Nodes = Number of non-trival Graal nodes created for this method during partial evaluation.");
         out.println("  Calls = Number of not expanded calls created for this method during partial evaluation.");
         out.printf(" %-11s |Nodes %5s %5s %5s %8s |Calls %5s %5s %5s %8s | Method Name%n", "Invocations", "Sum", "Min", "Max", "Avg", "Sum", "Min", "Max", "Avg");
-        histogram.values().stream().sorted().forEach(statistics -> statistics.print(out));
+        histogram.values().stream().filter(statistics -> statistics.shallowCount.getSum() > 0).sorted().forEach(statistics -> statistics.print(out));
     }
 
     private static class MethodStatistics implements Comparable<MethodStatistics> {
@@ -95,16 +109,16 @@
         }
 
         public void print(PrintStream out) {
-            out.printf(" %11d |        %5d %5d %5d %8.2f |      %5d %5d %5d %8.2f | %s%n", //
+            out.printf(" %11d |      %5d %5d %5d %8.2f |      %5d %5d %5d %8.2f | %s%n", //
                             count, shallowCount.getSum(), shallowCount.getMin(), shallowCount.getMax(), //
                             shallowCount.getAverage(), callCount.getSum(), callCount.getMin(), callCount.getMax(), //
                             callCount.getAverage(), method.format("%h.%n(%p)"));
         }
 
         public int compareTo(MethodStatistics o) {
-            int result = (int) (o.shallowCount.getSum() - shallowCount.getSum());
+            int result = Long.compare(o.shallowCount.getSum(), shallowCount.getSum());
             if (result == 0) {
-                return o.count - count;
+                return Integer.compare(o.count, count);
             }
             return result;
         }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/arithmetic/IntegerSubExactNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -94,10 +94,4 @@
     public void lower(LoweringTool tool) {
         IntegerExactArithmeticSplitNode.lower(tool, this);
     }
-
-    @NodeIntrinsic
-    public static native int subtractExact(int a, int b);
-
-    @NodeIntrinsic
-    public static native long subtractExact(long a, long b);
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/substitutions/TruffleGraphBuilderPlugins.java	Mon Mar 23 16:11:48 2015 +0100
@@ -32,7 +32,8 @@
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graphbuilderconf.*;
-import com.oracle.graal.graphbuilderconf.InvocationPlugins.*;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Receiver;
+import com.oracle.graal.graphbuilderconf.InvocationPlugins.Registration;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -68,9 +69,9 @@
     public static void registerOptimizedAssumptionPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, OptimizedAssumption.class);
         r.register1("isValid", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
-                if (arg.isConstant()) {
-                    Constant constant = arg.asConstant();
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                if (receiver.isConstant()) {
+                    Constant constant = receiver.get().asConstant();
                     OptimizedAssumption assumption = b.getSnippetReflection().asObject(OptimizedAssumption.class, (JavaConstant) constant);
                     b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(assumption.isValid())));
                     if (assumption.isValid()) {
@@ -89,31 +90,31 @@
         for (Kind kind : new Kind[]{Kind.Int, Kind.Long}) {
             Class<?> type = kind.toJavaClass();
             r.register2("addExact", type, type, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
                     b.push(kind.getStackKind(), b.append(new IntegerAddExactNode(x, y)));
                     return true;
                 }
             });
             r.register2("subtractExact", type, type, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
                     b.push(kind.getStackKind(), b.append(new IntegerSubExactNode(x, y)));
                     return true;
                 }
             });
             r.register2("multiplyExact", type, type, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
                     b.push(kind.getStackKind(), b.append(new IntegerMulExactNode(x, y)));
                     return true;
                 }
             });
             r.register2("multiplyHigh", type, type, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
                     b.push(kind.getStackKind(), b.append(new IntegerMulHighNode(x, y)));
                     return true;
                 }
             });
             r.register2("multiplyHighUnsigned", type, type, new InvocationPlugin() {
-                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
+                public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
                     b.push(kind.getStackKind(), b.append(new UnsignedMulHighNode(x, y)));
                     return true;
                 }
@@ -124,47 +125,47 @@
     public static void registerCompilerDirectivesPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, CompilerDirectives.class);
         r.register0("inInterpreter", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(false)));
                 return true;
             }
         });
         r.register0("inCompiledCode", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true)));
                 return true;
             }
         });
         r.register0("transferToInterpreter", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.append(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
         r.register0("transferToInterpreterAndInvalidate", new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 b.append(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter));
                 return true;
             }
         });
         r.register1("interpreterOnly", Runnable.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
                 return true;
             }
         });
         r.register1("interpreterOnly", Callable.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode arg) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
                 return true;
             }
         });
         r.register2("injectBranchProbability", double.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode probability, ValueNode condition) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode probability, ValueNode condition) {
                 b.push(Kind.Boolean.getStackKind(), b.append(new BranchProbabilityNode(probability, condition)));
                 return true;
             }
         });
         r.register1("bailout", String.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
                 if (message.isConstant()) {
                     throw b.bailout(message.asConstant().toValueString());
                 }
@@ -172,7 +173,7 @@
             }
         });
         r.register1("isCompilationConstant", Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 if ((value instanceof BoxNode ? ((BoxNode) value).getValue() : value).isConstant()) {
                     b.push(Kind.Boolean.getStackKind(), b.append(ConstantNode.forBoolean(true)));
                 } else {
@@ -182,7 +183,7 @@
             }
         });
         r.register1("materialize", Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 b.append(new ForceMaterializeNode(value));
                 return true;
             }
@@ -190,7 +191,7 @@
 
         r = new Registration(plugins, CompilerAsserts.class);
         r.register1("partialEvaluationConstant", Object.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
                 ValueNode curValue = value;
                 if (curValue instanceof BoxNode) {
                     BoxNode boxNode = (BoxNode) curValue;
@@ -215,7 +216,7 @@
             }
         });
         r.register1("neverPartOfCompilation", String.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode message) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode message) {
                 if (message.isConstant()) {
                     String messageString = message.asConstant().toValueString();
                     b.append(new NeverPartOfCompilationNode(messageString));
@@ -229,14 +230,14 @@
     public static void registerOptimizedCallTargetPlugins(MetaAccessProvider metaAccess, InvocationPlugins plugins) {
         Registration r = new Registration(plugins, OptimizedCallTarget.class);
         r.register2("createFrame", FrameDescriptor.class, Object[].class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode descriptor, ValueNode args) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode descriptor, ValueNode args) {
                 Class<?> frameClass = TruffleCompilerOptions.TruffleUseFrameWithoutBoxing.getValue() ? FrameWithoutBoxing.class : FrameWithBoxing.class;
                 b.push(Kind.Object, b.append(new NewFrameNode(StampFactory.exactNonNull(metaAccess.lookupJavaType(frameClass)), descriptor, args)));
                 return true;
             }
         });
         r.register2("castArrayFixedLength", Object[].class, int.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode args, ValueNode length) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode args, ValueNode length) {
                 b.push(Kind.Object, b.append(new PiArrayNode(args, length, args.stamp())));
                 return true;
             }
@@ -264,8 +265,8 @@
 
     private static void registerMaterialize(Registration r) {
         r.register1("materialize", Receiver.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode frame) {
-                b.push(Kind.Object, b.append(new MaterializeFrameNode(GraphBuilderContext.nullCheckedValue(b, frame))));
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver frame) {
+                b.push(Kind.Object, b.append(new MaterializeFrameNode(frame.get())));
                 return true;
             }
         });
@@ -273,7 +274,7 @@
 
     private static void registerUnsafeCast(Registration r) {
         r.register4("unsafeCast", Object.class, Class.class, boolean.class, boolean.class, new InvocationPlugin() {
-            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode clazz, ValueNode condition, ValueNode nonNull) {
                 if (clazz.isConstant() && nonNull.isConstant()) {
                     ConstantReflectionProvider constantReflection = b.getConstantReflection();
                     ResolvedJavaType javaType = constantReflection.asJavaType(clazz.asConstant());
@@ -331,7 +332,7 @@
             this.returnKind = returnKind;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode offset, ValueNode condition, ValueNode location) {
             if (location.isConstant()) {
                 LocationIdentity locationIdentity;
                 if (location.isNullConstant()) {
@@ -356,7 +357,7 @@
             this.kind = kind;
         }
 
-        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) {
+        public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode object, ValueNode offset, ValueNode value, ValueNode location) {
             ValueNode locationArgument = location;
             if (locationArgument.isConstant()) {
                 LocationIdentity locationIdentity;
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/OnAdoptTest.java	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.api.test;
-
-import org.junit.*;
-
-import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.frame.*;
-import com.oracle.truffle.api.nodes.*;
-
-/**
- * <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.
- * </p>
- */
-public class OnAdoptTest {
-
-    static class Root extends RootNode {
-
-        @Child private Base child1;
-        @Child private Base child2;
-
-        public Root(Base child1, Base child2) {
-            super(null);
-            this.child1 = child1;
-            this.child2 = child2;
-        }
-
-        @Override
-        public Object execute(VirtualFrame frame) {
-            return child1.executeInt(frame) + child2.executeInt(frame);
-        }
-
-    }
-
-    abstract static class Base extends Node {
-        public abstract int executeInt(VirtualFrame frame);
-    }
-
-    static class Wrapper extends Base {
-
-        @Child private Base wrappee;
-
-        public Wrapper(Base wrappee) {
-            this.wrappee = wrappee;
-        }
-
-        @Override
-        public int executeInt(VirtualFrame frame) {
-            return 1 + wrappee.executeInt(frame);
-        }
-
-    }
-
-    abstract static class GenBase extends Base {
-
-        private final int k;
-
-        public GenBase(int k) {
-            this.k = k;
-        }
-
-        @Override
-        public int executeInt(VirtualFrame frame) {
-            return k;
-        }
-
-    }
-
-    static class Gen extends GenBase {
-        public Gen(int k) {
-            super(k);
-        }
-    }
-
-    static class GenWrapped extends GenBase {
-
-        public GenWrapped(int k) {
-            super(k);
-        }
-
-        @Override
-        protected void onAdopt() {
-            Wrapper w = new Wrapper(this);
-            this.replace(w);
-        }
-
-    }
-
-    @Test
-    public void testOnInsert() {
-        TruffleRuntime runtime = Truffle.getRuntime();
-        Base b1 = new Gen(11);
-        Base b2 = new GenWrapped(11);
-        Root r = new Root(b1, b2);
-        CallTarget ct = runtime.createCallTarget(r);
-        Object result = ct.call();
-        Assert.assertEquals(23, result);
-    }
-
-}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultLoopNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -29,13 +29,20 @@
 
 public final class DefaultLoopNode extends LoopNode {
 
+    @Child private RepeatingNode repeatNode;
+
     public DefaultLoopNode(RepeatingNode repeatNode) {
-        super(repeatNode);
+        this.repeatNode = repeatNode;
+    }
+
+    @Override
+    public RepeatingNode getRepeatingNode() {
+        return repeatNode;
     }
 
     @Override
     public void executeLoop(VirtualFrame frame) {
-        while (executeRepeatingNode(frame)) {
+        while (repeatNode.executeRepeating(frame)) {
             // Empty
         }
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/LoopNode.java	Mon Mar 23 16:11:48 2015 +0100
@@ -31,20 +31,8 @@
  */
 public abstract class LoopNode extends Node {
 
-    @Child protected RepeatingNode repeatingNode;
-
-    public LoopNode(RepeatingNode repeatingNode) {
-        this.repeatingNode = repeatingNode;
-    }
-
     public abstract void executeLoop(VirtualFrame frame);
 
-    protected final boolean executeRepeatingNode(VirtualFrame frame) {
-        return getRepeatingNode().executeRepeating(frame);
-    }
-
-    public final RepeatingNode getRepeatingNode() {
-        return repeatingNode;
-    }
+    public abstract RepeatingNode getRepeatingNode();
 
 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java	Mon Mar 23 16:11:48 2015 +0100
@@ -176,15 +176,11 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
-        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         if (TruffleOptions.TraceASTJSON) {
             JSONHelper.dumpNewChild(this, newChild);
         }
         newChild.adoptHelper();
-        if (isInserted) {
-            newChild.onAdopt();
-        }
     }
 
     private void adoptHelper() {
@@ -201,12 +197,8 @@
         if (newChild == this) {
             throw new IllegalStateException("The parent of a node can never be the node itself.");
         }
-        boolean isInserted = newChild.parent == null;
         newChild.parent = this;
         newChild.adoptUnadoptedHelper();
-        if (isInserted) {
-            newChild.onAdopt();
-        }
     }
 
     private void adoptUnadoptedHelper() {
@@ -329,16 +321,6 @@
     }
 
     /**
-     * Subclasses of {@link Node} can implement this method to execute extra functionality when a
-     * node is effectively inserted into the AST. The {@code onAdopt} callback is called after the
-     * node has been effectively inserted, and it is guaranteed to be called only once for any given
-     * node.
-     */
-    protected void onAdopt() {
-        // empty default
-    }
-
-    /**
      * Invokes the {@link NodeVisitor#visit(Node)} method for this node and recursively also for all
      * child nodes.
      *
@@ -575,22 +557,19 @@
 
     private static final Object GIL = new Object();
 
-    private static final ThreadLocal<Integer> IN_ATOMIC_BLOCK = new ThreadLocal<>();
+    private static final ThreadLocal<Integer> IN_ATOMIC_BLOCK = new ThreadLocal<Integer>() {
+        @Override
+        protected Integer initialValue() {
+            return 0;
+        }
+    };
 
     private static boolean inAtomicBlock() {
-        Integer value = IN_ATOMIC_BLOCK.get();
-        if (value == null) {
-            return false;
-        }
-        return value > 0;
+        return IN_ATOMIC_BLOCK.get() > 0;
     }
 
     private static boolean enterAtomic() {
-        Integer currentValue = IN_ATOMIC_BLOCK.get();
-        if (currentValue == null) {
-            currentValue = 0;
-        }
-        IN_ATOMIC_BLOCK.set(currentValue + 1);
+        IN_ATOMIC_BLOCK.set(IN_ATOMIC_BLOCK.get() + 1);
         return true;
     }
 
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Mar 23 16:11:48 2015 +0100
@@ -155,14 +155,20 @@
 
         @Override
         public void putObject(Node receiver, Object value) {
-            assert !type.isPrimitive() && value == null || type.isInstance(value);
-            unsafe.putObject(receiver, offset, value);
+            if (!type.isPrimitive() && value == null || type.isInstance(value)) {
+                unsafe.putObject(receiver, offset, value);
+            } else {
+                throw new IllegalArgumentException();
+            }
         }
 
         @Override
         public Object getObject(Node receiver) {
-            assert !type.isPrimitive();
-            return unsafe.getObject(receiver, offset);
+            if (!type.isPrimitive()) {
+                return unsafe.getObject(receiver, offset);
+            } else {
+                throw new IllegalArgumentException();
+            }
         }
 
         @Override
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/utilities/ValueProfile.java	Mon Mar 23 16:11:48 2015 +0100
@@ -24,6 +24,8 @@
  */
 package com.oracle.truffle.api.utilities;
 
+import com.oracle.truffle.api.nodes.*;
+
 /**
  * Utility class to speculate on certain properties of values.
  *
@@ -42,7 +44,7 @@
  * @see #createIdentityProfile()
  * @see #createClassProfile()
  */
-public abstract class ValueProfile {
+public abstract class ValueProfile extends NodeCloneable {
 
     public abstract <T> T profile(T value);
 
--- a/mx/mx_graal.py	Mon Mar 23 15:58:36 2015 +0100
+++ b/mx/mx_graal.py	Mon Mar 23 16:11:48 2015 +0100
@@ -1425,18 +1425,29 @@
     mx.log('TOTAL TIME:   ' + '[' + str(allDuration) + ']')
 
 class Task:
+    # None or a list of strings. If not None, only tasks whose title
+    # matches at least one of the substrings in this list will return
+    # a non-None value from __enter__. The body of a 'with Task(...) as t'
+    # statement should check 't' and exit immediately if it is None.
+    filters = None
+
     def __init__(self, title, tasks=None):
-        self.start = time.time()
+        self.tasks = tasks
         self.title = title
-        self.end = None
-        self.duration = None
-        self.tasks = tasks
-        mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
+        self.skipped = Task.filters is not None and not any([f in title for f in Task.filters])
+        if not self.skipped:
+            self.start = time.time()
+            self.end = None
+            self.duration = None
+            mx.log(time.strftime('gate: %d %b %Y %H:%M:%S: BEGIN: ') + title)
     def __enter__(self):
         assert self.tasks is not None, "using Task with 'with' statement requires to pass the tasks list in the constructor"
+        if self.skipped:
+            return None
         return self
     def __exit__(self, exc_type, exc_value, traceback):
-        self.tasks.append(self.stop())
+        if not self.skipped:
+            self.tasks.append(self.stop())
     def stop(self):
         self.end = time.time()
         self.duration = datetime.timedelta(seconds=self.end - self.start)
@@ -1481,63 +1492,65 @@
 
 def _basic_gate_body(args, tasks):
     # Build server-hosted-graal now so we can run the unit tests
-    with Task('BuildHotSpotGraalHosted: product', tasks):
-        buildvms(['--vms', 'server', '--builds', 'product'])
+    with Task('BuildHotSpotGraalHosted: product', tasks) as t:
+        if t: buildvms(['--vms', 'server', '--builds', 'product'])
 
     # Run unit tests on server-hosted-graal
     with VM('server', 'product'):
-        with Task('UnitTests:hosted-product', tasks):
-            unittest(['--enable-timing', '--verbose', '--fail-fast'])
+        with Task('UnitTests:hosted-product', tasks) as t:
+            if t: unittest(['--enable-timing', '--verbose', '--fail-fast'])
 
     # Build the other VM flavors
-    with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks):
-        buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
+    with Task('BuildHotSpotGraalOthers: fastdebug,product', tasks) as t:
+        if t: buildvms(['--vms', 'graal,server', '--builds', 'fastdebug,product'])
 
     with VM('graal', 'fastdebug'):
-        with Task('BootstrapWithSystemAssertions:fastdebug', tasks):
-            vm(['-esa', '-XX:-TieredCompilation', '-version'])
+        with Task('BootstrapWithSystemAssertions:fastdebug', tasks) as t:
+            if t: vm(['-esa', '-XX:-TieredCompilation', '-version'])
 
     with VM('graal', 'fastdebug'):
-        with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks):
-            vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version'])
+        with Task('BootstrapEconomyWithSystemAssertions:fastdebug', tasks) as t:
+            if t: vm(['-esa', '-XX:-TieredCompilation', '-G:CompilerConfiguration=economy', '-version'])
 
     with VM('graal', 'fastdebug'):
-        with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks):
-            vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version'])
+        with Task('BootstrapWithSystemAssertionsNoCoop:fastdebug', tasks) as t:
+            if t: vm(['-esa', '-XX:-TieredCompilation', '-XX:-UseCompressedOops', '-version'])
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithGCVerification:product', tasks):
-            out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
-            vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
+        with Task('BootstrapWithGCVerification:product', tasks) as t:
+            if t:
+                out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
+                vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithG1GCVerification:product', tasks):
-            out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
-            vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
+        with Task('BootstrapWithG1GCVerification:product', tasks) as t:
+            if t:
+                out = mx.DuplicateSuppressingStream(['VerifyAfterGC:', 'VerifyBeforeGC:']).write
+                vm(['-XX:-TieredCompilation', '-XX:+UnlockDiagnosticVMOptions', '-XX:-UseSerialGC', '-XX:+UseG1GC', '-XX:+VerifyBeforeGC', '-XX:+VerifyAfterGC', '-version'], out=out)
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithRegisterPressure:product', tasks):
-            vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
+        with Task('BootstrapWithRegisterPressure:product', tasks) as t:
+            if t: vm(['-XX:-TieredCompilation', '-G:RegisterPressure=rbx,r11,r10,r14,xmm3,xmm11,xmm14', '-esa', '-version'])
 
     with VM('graal', 'product'):
-        with Task('BootstrapWithImmutableCode:product', tasks):
-            vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
+        with Task('BootstrapWithImmutableCode:product', tasks) as t:
+            if t: vm(['-XX:-TieredCompilation', '-G:+ImmutableCode', '-G:+VerifyPhases', '-esa', '-version'])
 
     for vmbuild in ['fastdebug', 'product']:
         for test in sanitycheck.getDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild) + sanitycheck.getScalaDacapos(level=sanitycheck.SanityCheckLevel.Gate, gateBuildLevel=vmbuild):
             with Task(str(test) + ':' + vmbuild, tasks) as t:
-                if not test.test('graal'):
+                if t and not test.test('graal'):
                     t.abort(test.name + ' Failed')
 
     # ensure -Xbatch still works
     with VM('graal', 'product'):
-        with Task('DaCapo_pmd:BatchMode:product', tasks):
-            dacapo(['-Xbatch', 'pmd'])
+        with Task('DaCapo_pmd:BatchMode:product', tasks) as t:
+            if t: dacapo(['-Xbatch', 'pmd'])
 
     # ensure -Xcomp still works
     with VM('graal', 'product'):
-        with Task('XCompMode:product', tasks):
-            vm(['-Xcomp', '-version'])
+        with Task('XCompMode:product', tasks) as t:
+            if t: vm(['-Xcomp', '-version'])
 
     if args.jacocout is not None:
         jacocoreport([args.jacocout])
@@ -1545,17 +1558,19 @@
     global _jacoco
     _jacoco = 'off'
 
-    with Task('CleanAndBuildIdealGraphVisualizer', tasks):
-        env = _igvFallbackJDK(os.environ)
-        buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
-        mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env)
+    with Task('CleanAndBuildIdealGraphVisualizer', tasks) as t:
+        if t:
+            env = _igvFallbackJDK(os.environ)
+            buildxml = mx._cygpathU2W(join(_graal_home, 'src', 'share', 'tools', 'IdealGraphVisualizer', 'build.xml'))
+            mx.run(['ant', '-f', buildxml, '-q', 'clean', 'build'], env=env)
 
     # Prevent Graal modifications from breaking the standard builds
     if args.buildNonGraal:
-        with Task('BuildHotSpotVarieties', tasks):
-            buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
-            if mx.get_os() not in ['windows', 'cygwin']:
-                buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized'])
+        with Task('BuildHotSpotVarieties', tasks) as t:
+            if t:
+                buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
+                if mx.get_os() not in ['windows', 'cygwin']:
+                    buildvms(['--vms', 'server-nograal', '--builds', 'product,optimized'])
 
         for vmbuild in ['product', 'fastdebug']:
             for theVm in ['client', 'server']:
@@ -1563,11 +1578,11 @@
                     mx.log('The' + theVm + ' VM is not supported on this platform')
                     continue
                 with VM(theVm, vmbuild):
-                    with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks):
-                        dacapo(['pmd'])
+                    with Task('DaCapo_pmd:' + theVm + ':' + vmbuild, tasks) as t:
+                        if t: dacapo(['pmd'])
 
-                    with Task('UnitTests:' + theVm + ':' + vmbuild, tasks):
-                        unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api'])
+                    with Task('UnitTests:' + theVm + ':' + vmbuild, tasks) as t:
+                        if t: unittest(['-XX:CompileCommand=exclude,*::run*', 'graal.api'])
 
 
 def gate(args, gate_body=_basic_gate_body):
@@ -1580,61 +1595,67 @@
     parser.add_argument('-j', '--omit-java-clean', action='store_false', dest='cleanJava', help='omit cleaning Java native code')
     parser.add_argument('-n', '--omit-native-clean', action='store_false', dest='cleanNative', help='omit cleaning and building native code')
     parser.add_argument('-g', '--only-build-graalvm', action='store_false', dest='buildNonGraal', help='only build the Graal VM')
+    parser.add_argument('-t', '--task-filter', help='comma separated list of substrings to select subset of tasks to be run')
     parser.add_argument('--jacocout', help='specify the output directory for jacoco report')
 
     args = parser.parse_args(args)
 
     global _jacoco
+    if args.task_filter:
+        Task.filters = args.task_filter.split(',')
 
     tasks = []
     total = Task('Gate')
     try:
-        with Task('Pylint', tasks):
-            mx.pylint([])
+        with Task('Pylint', tasks) as t:
+            if t: mx.pylint([])
 
         def _clean(name='Clean'):
-            with Task(name, tasks):
-                cleanArgs = []
-                if not args.cleanNative:
-                    cleanArgs.append('--no-native')
-                if not args.cleanJava:
-                    cleanArgs.append('--no-java')
-                clean(cleanArgs)
+            with Task(name, tasks) as t:
+                if t:
+                    cleanArgs = []
+                    if not args.cleanNative:
+                        cleanArgs.append('--no-native')
+                    if not args.cleanJava:
+                        cleanArgs.append('--no-java')
+                    clean(cleanArgs)
         _clean()
 
         with Task('IDEConfigCheck', tasks):
-            mx.ideclean([])
-            mx.ideinit([])
+            if t:
+                mx.ideclean([])
+                mx.ideinit([])
 
         eclipse_exe = mx.get_env('ECLIPSE_EXE')
         if eclipse_exe is not None:
             with Task('CodeFormatCheck', tasks) as t:
-                if mx.eclipseformat(['-e', eclipse_exe]) != 0:
+                if t and mx.eclipseformat(['-e', eclipse_exe]) != 0:
                     t.abort('Formatter modified files - run "mx eclipseformat", check in changes and repush')
 
         with Task('Canonicalization Check', tasks) as t:
-            mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...'))
-            if mx.canonicalizeprojects([]) != 0:
-                t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.')
+            if t:
+                mx.log(time.strftime('%d %b %Y %H:%M:%S - Ensuring mx/projects files are canonicalized...'))
+                if mx.canonicalizeprojects([]) != 0:
+                    t.abort('Rerun "mx canonicalizeprojects" and check-in the modified mx/projects files.')
 
         if mx.get_env('JDT'):
             with Task('BuildJavaWithEcj', tasks):
-                build(['-p', '--no-native', '--jdt-warning-as-error'])
+                if t: build(['-p', '--no-native', '--jdt-warning-as-error'])
             _clean('CleanAfterEcjBuild')
 
         with Task('BuildJavaWithJavac', tasks):
-            build(['-p', '--no-native', '--force-javac'])
+            if t: build(['-p', '--no-native', '--force-javac'])
 
         with Task('Checkstyle', tasks) as t:
-            if mx.checkstyle([]) != 0:
+            if t and mx.checkstyle([]) != 0:
                 t.abort('Checkstyle warnings were found')
 
         with Task('Checkheaders', tasks) as t:
-            if checkheaders([]) != 0:
+            if t and checkheaders([]) != 0:
                 t.abort('Checkheaders warnings were found')
 
         with Task('FindBugs', tasks) as t:
-            if findbugs([]) != 0:
+            if t and findbugs([]) != 0:
                 t.abort('FindBugs warnings were found')
 
         if exists('jacoco.exec'):
@@ -1663,6 +1684,9 @@
     mx.log('  =======')
     mx.log('  ' + str(total.duration))
 
+    if args.task_filter:
+        Task.filters = None
+
 def deoptalot(args):
     """bootstrap a fastdebug Graal VM with DeoptimizeALot and VerifyOops on
 
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Mon Mar 23 16:11:48 2015 +0100
@@ -86,7 +86,7 @@
         this.to = to;
         this.state = State.SAME;
         this.label = label;
-        this.type = type;
+        this.type = type.intern();
     }
 
     static WeakHashMap<InputEdge, WeakReference<InputEdge>> immutableCache = new WeakHashMap<>();
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java	Mon Mar 23 16:11:48 2015 +0100
@@ -271,7 +271,7 @@
             } else {
                 sb.append(", ");
             }
-            sb.append(p[0] + "=" + p[1]);
+            sb.append(p[0]).append("=").append(p[1]);
         }
         return sb.append("]").toString();
     }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Mon Mar 23 16:11:48 2015 +0100
@@ -706,7 +706,8 @@
     private void parseNodes(InputGraph graph) throws IOException {
         int count = readInt();
         Map<String, Object> props = new HashMap<>();
-        List<Edge> edges = new LinkedList<>();
+        List<Edge> inputEdges = new ArrayList<>(count);
+        List<Edge> succEdges = new ArrayList<>(count);
         for (int i = 0; i < count; i++) {
             int id = readInt();
             InputNode node = new InputNode(id);
@@ -733,7 +734,7 @@
                     props.put(key, value);
                 }
             }
-            int edgesStart = edges.size();
+            ArrayList<Edge> currentEdges = new ArrayList<>();
             int portNum = 0;
             for (TypedPort p : nodeClass.inputs) {
                 if (p.isList) {
@@ -741,14 +742,18 @@
                     for (int j = 0; j < size; j++) {
                         int in = readInt();
                         if (in >= 0) {
-                            edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true));
+                            Edge e = new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true);
+                            currentEdges.add(e);
+                            inputEdges.add(e);
                             portNum++;
                         }
                     }
                 } else {
                     int in = readInt();
                     if (in >= 0) {
-                        edges.add(new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true));
+                        Edge e = new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true);
+                        currentEdges.add(e);
+                        inputEdges.add(e);
                         portNum++;
                     }
                 }
@@ -761,19 +766,23 @@
                     for (int j = 0; j < size; j++) {
                         int sux = readInt();
                         if (sux >= 0) {
-                            edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false));
+                            Edge e = new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false);
+                            currentEdges.add(e);
+                            succEdges.add(e);
                             portNum++;
                         }
                     }
                 } else {
                     int sux = readInt();
                     if (sux >= 0) {
-                        edges.add(new Edge(id, sux, (char) portNum, p.name, "Successor", false));
+                        Edge e = new Edge(id, sux, (char) portNum, p.name, "Successor", false);
+                        currentEdges.add(e);
+                        succEdges.add(e);
                         portNum++;
                     }
                 }
             }
-            properties.setProperty("name", createName(edges.subList(edgesStart, edges.size()), props, nodeClass.nameTemplate));
+            properties.setProperty("name", createName(currentEdges, props, nodeClass.nameTemplate));
             properties.setProperty("class", nodeClass.className);
             switch (nodeClass.className) {
                 case "BeginNode":
@@ -786,9 +795,20 @@
             graph.addNode(node);
             props.clear();
         }
-        for (Edge e : edges) {
-            char fromIndex = e.input ? 1 : e.num;
-            char toIndex = e.input ? e.num : 0;
+        
+        Set<InputNode> nodesWithSuccessor = new HashSet<>();
+        
+        for (Edge e : succEdges) {
+            assert !e.input;
+            char fromIndex = e.num;
+            nodesWithSuccessor.add(graph.getNode(e.from));
+            char toIndex = 0;
+            graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type));
+        }
+        for (Edge e : inputEdges) {
+            assert e.input;
+            char fromIndex = (char) (nodesWithSuccessor.contains(graph.getNode(e.from)) ? 1 : 0);
+            char toIndex = e.num;
             graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type));
         }
     }
@@ -805,7 +825,7 @@
                 case "i":
                     StringBuilder inputString = new StringBuilder();
                     for(Edge edge : edges) {
-                        if (name.equals(edge.label)) {
+                        if (edge.label.startsWith(name) && (name.length() == edge.label.length() || edge.label.charAt(name.length()) == '[')) {
                             if (inputString.length() > 0) {
                                 inputString.append(", ");
                             }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Mon Mar 23 16:11:48 2015 +0100
@@ -75,6 +75,7 @@
     public static final String NODE_ID_PROPERTY = "id";
     public static final String FROM_PROPERTY = "from";
     public static final String TO_PROPERTY = "to";
+    public static final String TYPE_PROPERTY = "type";
     public static final String PROPERTY_NAME_PROPERTY = "name";
     public static final String GRAPH_NAME_PROPERTY = "name";
     public static final String FROM_INDEX_PROPERTY = "fromIndex";
@@ -387,6 +388,7 @@
             int from = -1;
             int to = -1;
             String label = null;
+            String type = null;
 
             try {
                 String fromIndexString = readAttribute(FROM_INDEX_PROPERTY);
@@ -403,6 +405,7 @@
                 }
 
                 label = readAttribute(LABEL_PROPERTY);
+                type = readAttribute(TYPE_PROPERTY);
 
                 from = lookupID(readRequiredAttribute(FROM_PROPERTY));
                 to = lookupID(readRequiredAttribute(TO_PROPERTY));
@@ -410,7 +413,7 @@
                 throw new SAXException(e);
             }
 
-            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, "");
+            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, type == null ? "" : type);
             return start(conn);
         }
 
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java	Mon Mar 23 16:11:48 2015 +0100
@@ -240,6 +240,7 @@
         }
         p.setProperty(Parser.TO_PROPERTY, Integer.toString(edge.getTo()));
         p.setProperty(Parser.FROM_PROPERTY, Integer.toString(edge.getFrom()));
+        p.setProperty(Parser.TYPE_PROPERTY, edge.getType());
         return p;
     }
 }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd	Mon Mar 23 16:11:48 2015 +0100
@@ -109,6 +109,7 @@
         <xsd:attribute name="from" type="xsd:int" use="required" />
         <xsd:attribute name="to" type="xsd:int" use="required" />
         <xsd:attribute name="label" type="xsd:string" use="optional" />
+        <xsd:attribute name="type" type="xsd:string" use="optional" />
         <xsd:attribute name="fromIndex" type="xsd:int" use="optional" />
         
         <!-- These are aliases and should be mutually exclusive -->
--- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml	Mon Mar 23 16:11:48 2015 +0100
@@ -4,6 +4,13 @@
 ***         EDIT ../build.xml INSTEAD         ***
 -->
 <project name="com.sun.hotspot.igv.filterwindow-impl" basedir="..">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
     <property file="nbproject/private/suite-private.properties"/>
     <property file="nbproject/suite.properties"/>
     <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
@@ -16,13 +23,21 @@
             <property name="@{name}" value="${@{value}}"/>
         </sequential>
     </macrodef>
+    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="property"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{property}" value="@{value}"/>
+        </sequential>
+    </macrodef>
     <property file="${user.properties.file}"/>
     <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
-    <nbmproject2:property name="netbeans.dest.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
-    <fail message="You must define 'nbplatform.${nbplatform.active}.harness.dir'">
+    <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
         <condition>
             <not>
-                <available file="${harness.dir}" type="dir"/>
+                <contains string="${cluster.path.evaluated}" substring="platform"/>
             </not>
         </condition>
     </fail>
--- a/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties	Mon Mar 23 16:11:48 2015 +0100
@@ -1,5 +1,5 @@
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
 nbproject/build-impl.xml.data.CRC32=09ba2a87
-nbproject/build-impl.xml.script.CRC32=19fb08e0
-nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1
+nbproject/build-impl.xml.script.CRC32=e4293f0e
+nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1
--- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml	Mon Mar 23 16:11:48 2015 +0100
@@ -4,6 +4,13 @@
 ***         EDIT ../build.xml INSTEAD         ***
 -->
 <project name="com.sun.hotspot.igv.graal-impl" basedir="..">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
     <property file="nbproject/private/suite-private.properties"/>
     <property file="nbproject/suite.properties"/>
     <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
@@ -16,13 +23,21 @@
             <property name="@{name}" value="${@{value}}"/>
         </sequential>
     </macrodef>
+    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="property"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{property}" value="@{value}"/>
+        </sequential>
+    </macrodef>
     <property file="${user.properties.file}"/>
     <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
-    <nbmproject2:property name="netbeans.dest.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
-    <fail message="You must define 'nbplatform.${nbplatform.active}.harness.dir'">
+    <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
         <condition>
             <not>
-                <available file="${harness.dir}" type="dir"/>
+                <contains string="${cluster.path.evaluated}" substring="platform"/>
             </not>
         </condition>
     </fail>
--- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties	Mon Mar 23 16:11:48 2015 +0100
@@ -4,5 +4,5 @@
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
 nbproject/build-impl.xml.data.CRC32=79002a09
-nbproject/build-impl.xml.script.CRC32=7ac2ee25
-nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1
+nbproject/build-impl.xml.script.CRC32=2867f2d5
+nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1
--- a/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml	Mon Mar 23 16:11:48 2015 +0100
@@ -23,6 +23,14 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>com.sun.hotspot.igv.layout</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>com.sun.hotspot.igv.graph</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,7 +33,6 @@
 import java.awt.Color;
 import java.util.HashMap;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
  * Filter that colors usage and successor edges differently.
@@ -42,7 +41,7 @@
  */
 public class GraalEdgeColorFilter extends AbstractFilter {
 
-    private HashMap<String,Color> usageColor = new HashMap<>();
+    private final HashMap<String,Color> usageColor = new HashMap<>();
     private Color otherUsageColor = Color.BLACK;
 
     public GraalEdgeColorFilter() {
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-var f = new CombineFilter("Combine Filter");
-f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", ".*"), new Properties.RegexpPropertyMatcher("class", "BeginNode"), false, "shortName"));
-f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", "EndNode"), new Properties.RegexpPropertyMatcher("class", ".*"), true, "shortName"));
-f.apply(graph);
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Mon Mar 23 16:11:48 2015 +0100
@@ -1,5 +1,5 @@
 colorize("name", ".*", white);
-colorize("name", "Begin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange);
+colorize("name", "Begin|KillingBegin|EndNode|LoopBegin|LoopEnd|LoopExit|Return", orange);
 colorize("name", "Phi.*|ValueProxy", magenta);
 colorize("name", "FrameState@.*", new java.awt.Color(0.5, 0.8, 1.0));
 colorize("name", "If|Merge", pink);
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter	Mon Mar 23 15:58:36 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-colorize("class", "FrameState", red);
-colorize("locks", "", gray);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter	Mon Mar 23 16:11:48 2015 +0100
@@ -0,0 +1,3 @@
+split("class", "ConstantLocationNode");
+split("class", "ParameterNode");
+split("class", "ConstantNode");
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Mon Mar 23 16:11:48 2015 +0100
@@ -18,7 +18,7 @@
             <attr name="enabled" boolvalue="false"/>
         </file>
         
-        <file name="Graal Reduce Begin-End" url="filters/beginend.filter">
+        <file name="Graal Reduce Edges" url="filters/reduceEdges.filter">
             <attr name="enabled" boolvalue="false"/>
         </file>
         
@@ -26,10 +26,6 @@
             <attr name="enabled" boolvalue="false"/>
         </file>
         
-        <file name="Graal Mark FrameState With Lock" url="filters/framestatelocks.filter">
-            <attr name="enabled" boolvalue="false"/>
-        </file>
-        
         <file name="Graal Call Analysis" url="filters/callgraph.filter">
             <attr name="enabled" boolvalue="false"/>
         </file>
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Mon Mar 23 16:11:48 2015 +0100
@@ -41,8 +41,9 @@
     private InputGraph graph;
     private int curId;
     private String nodeText;
-    private Font font;
-    private Font slotFont;
+    private final Font font;
+    private final Font slotFont;
+    private final Font boldFont;
 
     public Font getFont() {
         return font;
@@ -51,12 +52,17 @@
     public Font getSlotFont() {
         return slotFont;
     }
+
+    public Font getBoldFont() {
+        return boldFont;
+    }
     
     private Diagram() {
         figures = new ArrayList<>();
         this.nodeText = "";
-        this.font = new Font("Arial", Font.PLAIN, 13);
+        this.font = new Font("Arial", Font.PLAIN, 12);
         this.slotFont = new Font("Arial", Font.PLAIN, 10);
+        this.boldFont = this.font.deriveFont(Font.BOLD);
     }
 
     public String getNodeText() {
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,14 +33,10 @@
 import java.util.List;
 import java.util.*;
 
-/**
- *
- * @author Thomas Wuerthinger
- */
 public class Figure extends Properties.Entity implements Source.Provider, Vertex {
 
-    public static final int INSET = 12;
-    public static int SLOT_WIDTH = 12;
+    public static final int INSET = 8;
+    public static int SLOT_WIDTH = 10;
     public static final int OVERLAPPING = 6;
     public static final int SLOT_START = 4;
     public static final int SLOT_OFFSET = 8;
--- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Mon Mar 23 16:11:48 2015 +0100
@@ -43,8 +43,8 @@
     public static final int CROSSING_ITERATIONS = 2;
     public static final int DUMMY_HEIGHT = 1;
     public static final int DUMMY_WIDTH = 1;
-    public static final int X_OFFSET = 9;
-    public static final int LAYER_OFFSET = 30;
+    public static final int X_OFFSET = 8;
+    public static final int LAYER_OFFSET = 8;
     public static final int MAX_LAYER_LENGTH = -1;
     public static final int MIN_LAYER_DIFFERENCE = 1;
     public static final int VIP_BONUS = 10;
@@ -75,8 +75,6 @@
     private LayoutGraph graph;
     private List<LayoutNode>[] layers;
     private int layerCount;
-    private Set<? extends Vertex> firstLayerHint;
-    private Set<? extends Vertex> lastLayerHint;
     private Set<? extends Link> importantLinks;
     private Set<Link> linksToFollow;
 
@@ -181,17 +179,15 @@
 
     @Override
     public void doLayout(LayoutGraph graph) {
-        doLayout(graph, new HashSet<Vertex>(), new HashSet<Vertex>(), new HashSet<Link>());
+        doLayout(graph, new HashSet<Link>());
 
     }
 
     @Override
-    public void doLayout(LayoutGraph graph, Set<? extends Vertex> firstLayerHint, Set<? extends Vertex> lastLayerHint, Set<? extends Link> importantLinks) {
+    public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks) {
 
         this.importantLinks = importantLinks;
         this.graph = graph;
-        this.firstLayerHint = firstLayerHint;
-        this.lastLayerHint = lastLayerHint;
 
         vertexToLayoutNode = new HashMap<>();
         reversedLinks = new HashSet<>();
@@ -219,7 +215,6 @@
             }
 
             for (LayoutEdge e : tmpArr) {
-                //System.out.println("Removed " + e);
                 e.from.succs.remove(e);
                 e.to.preds.remove(e);
             }
@@ -302,8 +297,6 @@
 
                         Collections.reverse(points);
 
-
-
                         if (cur.vertex == null && cur.preds.size() == 0) {
 
                             if (reversedLinkEndPoints.containsKey(e.link)) {
@@ -364,7 +357,7 @@
                         LayoutNode cur = e.to;
                         LayoutNode other = e.from;
                         LayoutEdge curEdge = e;
-                        while (cur.vertex == null && cur.succs.size() != 0) {
+                        while (cur.vertex == null && !cur.succs.isEmpty()) {
                             if (points.size() > 1 && points.get(points.size() - 1).x == cur.x + cur.width / 2 && points.get(points.size() - 2).x == cur.x + cur.width / 2) {
                                 points.remove(points.size() - 1);
                             }
@@ -373,7 +366,7 @@
                                 points.remove(points.size() - 1);
                             }
                             points.add(new Point(cur.x + cur.width / 2, cur.y + cur.height));
-                            if (cur.succs.size() == 0) {
+                            if (cur.succs.isEmpty()) {
                                 break;
                             }
                             assert cur.succs.size() == 1;
@@ -381,15 +374,13 @@
                             cur = curEdge.to;
                         }
 
-
                         p = new Point(cur.x + curEdge.relativeTo, cur.y + cur.yOffset + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y));
                         points.add(p);
                         if (curEdge.to.inOffsets.containsKey(curEdge.relativeTo)) {
                             points.add(new Point(p.x, p.y + curEdge.to.inOffsets.get(curEdge.relativeTo) + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y)));
                         }
 
-
-                        if (cur.succs.size() == 0 && cur.vertex == null) {
+                        if (cur.succs.isEmpty() && cur.vertex == null) {
                             if (reversedLinkStartPoints.containsKey(e.link)) {
                                 for (Point p1 : reversedLinkStartPoints.get(e.link)) {
                                     points.add(0, new Point(p1.x + other.x, p1.y + other.y));
@@ -528,13 +519,34 @@
     private static final Comparator<LayoutNode> nodeProcessingDownComparator = new Comparator<LayoutNode>() {
         @Override
         public int compare(LayoutNode n1, LayoutNode n2) {
+            int n1VIP = 0;
+            for (LayoutEdge e : n1.preds) {
+                if (e.vip) {
+                    n1VIP++;
+                }
+            }
+            int n2VIP = 0;
+            for (LayoutEdge e : n2.preds) {
+                if (e.vip) {
+                    n2VIP++;
+                }
+            }
+            if (n1VIP != n2VIP) {
+                return n2VIP - n1VIP;
+            }
             if (n1.vertex == null) {
                 if (n2.vertex == null) {
                     return 0;
                 }
+                if (n1.preds.size() == 1 && n1.preds.get(0).from.vertex != null) {
+                    return 1;
+                }
                 return -1;
             }
             if (n2.vertex == null) {
+                if (n2.preds.size() == 1 && n2.preds.get(0).from.vertex != null) {
+                    return -1;
+                }
                 return 1;
             }
             return n1.preds.size() - n2.preds.size();
@@ -544,15 +556,36 @@
 
         @Override
         public int compare(LayoutNode n1, LayoutNode n2) {
+            int n1VIP = 0;
+            for (LayoutEdge e : n1.succs) {
+                if (e.vip) {
+                    n1VIP++;
+                }
+            }
+            int n2VIP = 0;
+            for (LayoutEdge e : n2.succs) {
+                if (e.vip) {
+                    n2VIP++;
+                }
+            }
             if (n1.vertex == null) {
                 if (n2.vertex == null) {
                     return 0;
                 }
+                if (n1.succs.size() == 1 && n1.succs.get(0).to.vertex != null) {
+                    return 1;
+                }
                 return -1;
             }
             if (n2.vertex == null) {
+                if (n2.succs.size() == 1 && n2.succs.get(0).to.vertex != null) {
+                    return -1;
+                }
                 return 1;
             }
+            if (n1VIP != n2VIP) {
+                return n2VIP - n1VIP;
+            }
             return n1.succs.size() - n2.succs.size();
         }
     };
@@ -568,7 +601,7 @@
                 n.x = space[n.layer].get(n.pos);
             }
         }
-        
+
         @SuppressWarnings("unchecked")
         private void createArrays() {
             space = new ArrayList[layers.length];
@@ -600,13 +633,23 @@
             initialPositions();
             for (int i = 0; i < SWEEP_ITERATIONS; i++) {
                 sweepDown();
+                adjustSpace();
                 sweepUp();
+                adjustSpace();
             }
- 
+
             sweepDown();
-            //for (int i = 0; i < SWEEP_ITERATIONS; i++) {
-            //    doubleSweep();
-            //}            
+        }
+
+        private void adjustSpace() {
+            for (int i = 0; i < layers.length; i++) {
+                //               space[i] = new ArrayList<>();
+                int curX = 0;
+                for (LayoutNode n : layers[i]) {
+                    space[i].add(n.x);
+//                    curX += n.width + xOffset;
+                }
+            }
         }
 
         private int calculateOptimalDown(LayoutNode n) {
@@ -614,22 +657,38 @@
             if (size == 0) {
                 return n.x;
             }
-            int[] values = new int[size];
-            for (int i = 0; i < size; i++) {
-                LayoutEdge e = n.preds.get(i);
-                values[i] = e.from.x + e.relativeFrom - e.relativeTo;
+            int vipCount = 0;
+            for (LayoutEdge e : n.preds) {
                 if (e.vip) {
-                    return values[i];
+                    vipCount++;
                 }
             }
-            return median(values);
+
+            if (vipCount == 0) {
+                int[] values = new int[size];
+                for (int i = 0; i < size; i++) {
+                    LayoutEdge e = n.preds.get(i);
+                    values[i] = e.from.x + e.relativeFrom - e.relativeTo;
+                }
+                return median(values);
+            } else {
+                int z = 0;
+                int[] values = new int[vipCount];
+                for (int i = 0; i < size; i++) {
+                    LayoutEdge e = n.preds.get(i);
+                    if (e.vip) {
+                        values[z++] = e.from.x + e.relativeFrom - e.relativeTo;
+                    }
+                }
+                return median(values);
+            }
         }
 
         private int calculateOptimalBoth(LayoutNode n) {
             if (n.preds.size() == n.succs.size()) {
                 return n.x;
             }
-            
+
             int[] values = new int[n.preds.size() + n.succs.size()];
             int i = 0;
 
@@ -747,7 +806,7 @@
                     n.x = pos;
                 }
 
-                assert minX <= maxX;
+                assert minX <= maxX : minX + " vs " + maxX;
             }
 
             treeSet.add(n);
@@ -769,7 +828,7 @@
                 assert n.layer < layerCount;
             }
         }
-        
+
         @SuppressWarnings("unchecked")
         private void createLayers() {
             layers = new List[layerCount];
@@ -789,7 +848,7 @@
                 if (n.layer == 0) {
                     layers[0].add(n);
                     visited.add(n);
-                } else if (n.preds.size() == 0) {
+                } else if (n.preds.isEmpty()) {
                     layers[n.layer].add(n);
                     visited.add(n);
                 }
@@ -806,7 +865,6 @@
                 }
             }
 
-
             updatePositions();
 
             initX();
@@ -816,11 +874,7 @@
                 downSweep();
                 upSweep();
             }
-            if (reversedLinks.isEmpty()) {
-                // This graph seems to be a tree or forest.
-                // A final down-sweep will usually give us a better layout.
-                downSweep();
-            }
+            downSweep();
         }
 
         private void initX() {
@@ -869,8 +923,8 @@
                         if (e.vip) {
                             factor = VIP_BONUS;
                         }
-                        sum += cur*factor;
-                        count+=factor;
+                        sum += cur * factor;
+                        count += factor;
                     }
 
                     if (count > 0) {
@@ -879,7 +933,6 @@
                     }
                 }
 
-
                 updateCrossingNumbers(i, true);
                 Collections.sort(layers[i], crossingNodeComparator);
                 updateXOfLayer(i);
@@ -940,8 +993,8 @@
                         if (e.vip) {
                             factor = VIP_BONUS;
                         }
-                        sum += cur*factor;
-                        count+=factor;
+                        sum += cur * factor;
+                        count += factor;
                     }
 
                     if (count > 0) {
@@ -1012,7 +1065,7 @@
                 }
 
                 curY += maxHeight + baseLine + bottomBaseLine;
-                curY += layerOffset + (int) Math.sqrt(maxXOffset);
+                curY += layerOffset + ((int) (Math.sqrt(maxXOffset) * 1.5));
             }
         }
     }
@@ -1041,7 +1094,6 @@
         protected void run() {
             oldNodeCount = nodes.size();
 
-
             if (combine == Combine.SAME_OUTPUTS) {
 
                 Comparator<LayoutEdge> comparator = new Comparator<LayoutEdge>() {
@@ -1154,7 +1206,6 @@
                                     maxLayer = Math.max(maxLayer, curEdge.to.layer);
                                 }
 
-
                                 int cnt = maxLayer - n.layer - 1;
                                 LayoutEdge[] edges = new LayoutEdge[cnt];
                                 LayoutNode[] nodes = new LayoutNode[cnt];
@@ -1279,91 +1330,109 @@
 
         @Override
         protected void run() {
-
-            List<LayoutNode> insertOrder = new ArrayList<>();
+            assignLayerDownwards();
+            assignLayerUpwards();
+        }
 
-            HashSet<LayoutNode> set = new HashSet<>();
+        private void assignLayerDownwards() {
+            ArrayList<LayoutNode> hull = new ArrayList<>();
             for (LayoutNode n : nodes) {
-                if (n.preds.size() == 0) {
-                    set.add(n);
-                    insertOrder.add(n);
+                if (n.preds.isEmpty()) {
+                    hull.add(n);
                     n.layer = 0;
                 }
             }
 
             int z = minLayerDifference;
-            HashSet<LayoutNode> newSet = new HashSet<>();
-            HashSet<LayoutNode> failed = new HashSet<>();
-            while (!set.isEmpty()) {
-
-                newSet.clear();
-                failed.clear();
-
-                for (LayoutNode n : set) {
-
+            while (!hull.isEmpty()) {
+                ArrayList<LayoutNode> newSet = new ArrayList<>();
+                for (LayoutNode n : hull) {
                     for (LayoutEdge se : n.succs) {
                         LayoutNode s = se.to;
-                        if (!newSet.contains(s) && !failed.contains(s)) {
-                            boolean ok = true;
+                        if (s.layer != -1) {
+                            // This node was assigned before.
+                        } else {
+                            boolean unassignedPred = false;
                             for (LayoutEdge pe : s.preds) {
                                 LayoutNode p = pe.from;
-                                if (p.layer == -1) {
-                                    ok = false;
+                                if (p.layer == -1 || p.layer >= z) {
+                                    // This now has an unscheduled successor or a successor that was scheduled only in this round.
+                                    unassignedPred = true;
                                     break;
                                 }
                             }
 
-                            if (ok) {
+                            if (unassignedPred) {
+                                // This successor node can not yet be assigned.
+                            } else {
+                                s.layer = z;
                                 newSet.add(s);
-                            } else {
-                                failed.add(s);
                             }
                         }
                     }
-
                 }
 
-                for (LayoutNode n : newSet) {
-                    n.layer = z;
-                    insertOrder.add(n);
-                }
-
-                // Swap sets
-                HashSet<LayoutNode> tmp = set;
-                set = newSet;
-                newSet = tmp;
+                hull = newSet;
                 z += minLayerDifference;
             }
 
-            optimize(insertOrder);
+            layerCount = z - minLayerDifference;
+            for (LayoutNode n : nodes) {
+                n.layer = (layerCount - 1 - n.layer);
+            }
+        }
+
+        private void assignLayerUpwards() {
+            ArrayList<LayoutNode> hull = new ArrayList<>();
+            for (LayoutNode n : nodes) {
+                if (n.succs.isEmpty()) {
+                    hull.add(n);
+                } else {
+                    n.layer = -1;
+                }
+            }
+
+            int z = minLayerDifference;
+            while (!hull.isEmpty()) {
+                ArrayList<LayoutNode> newSet = new ArrayList<>();
+                for (LayoutNode n : hull) {
+                    if (n.layer < z) {
+                        for (LayoutEdge se : n.preds) {
+                            LayoutNode s = se.from;
+                            if (s.layer != -1) {
+                                // This node was assigned before.
+                            } else {
+                                boolean unassignedSucc = false;
+                                for (LayoutEdge pe : s.succs) {
+                                    LayoutNode p = pe.to;
+                                    if (p.layer == -1 || p.layer >= z) {
+                                        // This now has an unscheduled successor or a successor that was scheduled only in this round.
+                                        unassignedSucc = true;
+                                        break;
+                                    }
+                                }
+
+                                if (unassignedSucc) {
+                                    // This predecessor node can not yet be assigned.
+                                } else {
+                                    s.layer = z;
+                                    newSet.add(s);
+                                }
+                            }
+                        }
+                    } else {
+                        newSet.add(n);
+                    }
+                }
+
+                hull = newSet;
+                z += minLayerDifference;
+            }
 
             layerCount = z - minLayerDifference;
 
-            for (Vertex v : lastLayerHint) {
-
-                LayoutNode n = vertexToLayoutNode.get(v);
-                assert n.succs.size() == 0;
-                n.layer = layerCount - 1;
-            }
-
-            for (Vertex v : firstLayerHint) {
-                LayoutNode n = vertexToLayoutNode.get(v);
-                assert n.preds.size() == 0;
-                n.layer = 0;
-                assert n.layer == 0;
-            }
-        }
-
-        public void optimize(List<LayoutNode> insertOrder) {
-            for (int i = insertOrder.size() - 1; i >= 0; i--) {
-                LayoutNode cur = insertOrder.get(i);
-                if (cur.succs.size() > cur.preds.size()) {
-                    int minLayer = cur.succs.get(0).to.layer;
-                    for (LayoutEdge e : cur.succs) {
-                        minLayer = Math.min(minLayer, e.to.layer);
-                    }
-                    cur.layer = minLayer - 1;
-                }
+            for (LayoutNode n : nodes) {
+                n.layer = (layerCount - 1 - n.layer);
             }
         }
 
@@ -1415,7 +1484,6 @@
                 }
             }
 
-
             // Start DFS and reverse back edges
             visited = new HashSet<>();
             active = new HashSet<>();
@@ -1423,7 +1491,6 @@
                 DFS(node);
             }
 
-
             for (LayoutNode node : nodes) {
 
                 SortedSet<Integer> reversedDown = new TreeSet<>();
@@ -1434,7 +1501,6 @@
                     }
                 }
 
-
                 SortedSet<Integer> reversedUp = null;
                 if (reversedDown.size() == 0) {
                     reversedUp = new TreeSet<>(Collections.reverseOrder());
@@ -1522,7 +1588,6 @@
                     curX += offset;
                     node.bottomYOffset += offset;
 
-
                     endPoints.add(new Point(pos, node.height));
                     endPoints.add(new Point(pos, oldNodeHeight));
                     for (LayoutEdge e : reversedPreds) {
@@ -1530,7 +1595,6 @@
                     }
                 }
 
-
                 if (minX < 0) {
                     for (LayoutEdge e : node.preds) {
                         e.relativeTo -= minX;
@@ -1650,6 +1714,13 @@
 
         @Override
         public int compare(Link l1, Link l2) {
+            if (l1.isVIP() && !l2.isVIP()) {
+                return -1;
+            }
+            
+            if (!l1.isVIP() && l2.isVIP()) {
+                return 1;
+            }
 
             int result = l1.getFrom().getVertex().compareTo(l2.getFrom().getVertex());
             if (result != 0) {
@@ -1698,15 +1769,15 @@
                 edge.relativeFrom = l.getFrom().getRelativePosition().x;
                 edge.relativeTo = l.getTo().getRelativePosition().x;
                 edge.link = l;
+                edge.vip = l.isVIP();
                 edge.from.succs.add(edge);
                 edge.to.preds.add(edge);
-                edge.vip = l.isVIP();
-            //assert edge.from != edge.to; // No self-loops allowed
+                //assert edge.from != edge.to; // No self-loops allowed
             }
 
             for (Link l : importantLinks) {
-                if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex()) ||
-                        vertexToLayoutNode.containsKey(l.getTo().getVertex())) {
+                if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex())
+                        || vertexToLayoutNode.containsKey(l.getTo().getVertex())) {
                     continue;
                 }
                 LayoutNode from = vertexToLayoutNode.get(l.getFrom().getVertex());
--- a/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java	Mon Mar 23 16:11:48 2015 +0100
@@ -33,7 +33,7 @@
 
     public void doLayout(LayoutGraph graph);
 
-    public void doLayout(LayoutGraph graph, Set<? extends Vertex> firstLayerHint, Set<? extends Vertex> lastLayerHint, Set<? extends Link> importantLinks);
+    public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks);
 
     public void doRouting(LayoutGraph graph);
 }
--- a/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml	Mon Mar 23 16:11:48 2015 +0100
@@ -4,6 +4,13 @@
 ***         EDIT ../build.xml INSTEAD         ***
 -->
 <project name="com.sun.hotspot.igv.selectioncoordinator-impl" basedir="..">
+    <fail message="Please build using Ant 1.7.1 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.7.1"/>
+            </not>
+        </condition>
+    </fail>
     <property file="nbproject/private/suite-private.properties"/>
     <property file="nbproject/suite.properties"/>
     <fail unless="suite.dir">You must set 'suite.dir' to point to your containing module suite</fail>
@@ -16,13 +23,21 @@
             <property name="@{name}" value="${@{value}}"/>
         </sequential>
     </macrodef>
+    <macrodef name="evalprops" uri="http://www.netbeans.org/ns/nb-module-project/2">
+        <attribute name="property"/>
+        <attribute name="value"/>
+        <sequential>
+            <property name="@{property}" value="@{value}"/>
+        </sequential>
+    </macrodef>
     <property file="${user.properties.file}"/>
     <nbmproject2:property name="harness.dir" value="nbplatform.${nbplatform.active}.harness.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
-    <nbmproject2:property name="netbeans.dest.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
-    <fail message="You must define 'nbplatform.${nbplatform.active}.harness.dir'">
+    <nbmproject2:property name="nbplatform.active.dir" value="nbplatform.${nbplatform.active}.netbeans.dest.dir" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <nbmproject2:evalprops property="cluster.path.evaluated" value="${cluster.path}" xmlns:nbmproject2="http://www.netbeans.org/ns/nb-module-project/2"/>
+    <fail message="Path to 'platform' cluster missing in $${cluster.path} property or using corrupt Netbeans Platform (missing harness).">
         <condition>
             <not>
-                <available file="${harness.dir}" type="dir"/>
+                <contains string="${cluster.path.evaluated}" substring="platform"/>
             </not>
         </condition>
     </fail>
--- a/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties	Mon Mar 23 16:11:48 2015 +0100
@@ -1,5 +1,5 @@
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
 nbproject/build-impl.xml.data.CRC32=13553862
-nbproject/build-impl.xml.script.CRC32=5dca457e
-nbproject/build-impl.xml.stylesheet.CRC32=68e521fc@2.62.1
+nbproject/build-impl.xml.script.CRC32=3db87c68
+nbproject/build-impl.xml.stylesheet.CRC32=238281d1@2.67.1
--- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java	Mon Mar 23 16:11:48 2015 +0100
@@ -34,7 +34,7 @@
  */
 public class ColorIcon implements Icon {
 
-    private Color color;
+    private final Color color;
 
     public ColorIcon(Color c) {
         color = c;
@@ -42,8 +42,10 @@
 
     @Override
     public void paintIcon(Component c, Graphics g, int x, int y) {
+        Color oldColor = g.getColor();
         g.setColor(color);
         g.fillRect(x, y, 16, 16);
+        g.setColor(oldColor);
     }
 
     @Override
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Mon Mar 23 16:11:48 2015 +0100
@@ -71,6 +71,7 @@
     private Lookup lookup;
     private InstanceContent content;
     private Action[] actions;
+    private Action[] actionsWithSelection;
     private LayerWidget connectionLayer;
     private JScrollPane scrollPane;
     private UndoRedo.Manager undoRedoManager;
@@ -100,7 +101,7 @@
     public static final float ZOOM_MAX_FACTOR = 3.0f;
     public static final float ZOOM_MIN_FACTOR = 0.0f;//0.15f;
     public static final float ZOOM_INCREMENT = 1.5f;
-    public static final int SLOT_OFFSET = 6;
+    public static final int SLOT_OFFSET = 8;
     public static final int ANIMATION_LIMIT = 40;
     
     private PopupMenuProvider popupMenuProvider = new PopupMenuProvider() {
@@ -374,9 +375,10 @@
         }
     };
 
-    public DiagramScene(Action[] actions, DiagramViewModel model) {
+    public DiagramScene(Action[] actions, Action[] actionsWithSelection, DiagramViewModel model) {
 
         this.actions = actions;
+        this.actionsWithSelection = actionsWithSelection;
 
         content = new InstanceContent();
         lookup = new AbstractLookup(content);
@@ -399,6 +401,9 @@
         blockLayer = new LayerWidget(this);
         this.addChild(blockLayer);
 
+        connectionLayer = new LayerWidget(this);
+        this.addChild(connectionLayer);
+
         mainLayer = new LayerWidget(this);
         this.addChild(mainLayer);
 
@@ -410,9 +415,6 @@
         bottomRight.setPreferredLocation(new Point(-BORDER_SIZE, -BORDER_SIZE));
         this.addChild(bottomRight);
 
-        connectionLayer = new LayerWidget(this);
-        this.addChild(connectionLayer);
-
         LayerWidget selectionLayer = new LayerWidget(this);
         this.addChild(selectionLayer);
 
@@ -451,12 +453,21 @@
     }
     
     public boolean isAllVisible() {
-        return getModel().getHiddenNodes().size() == 0;
+        return getModel().getHiddenNodes().isEmpty();
     }
 
     public Action createGotoAction(final Figure f) {
         final DiagramScene diagramScene = this;
-        Action a = new AbstractAction() {
+        String name = f.getLines()[0];
+
+        name += " (";
+
+        final boolean hidden = !this.getWidget(f, FigureWidget.class).isVisible();
+        if (hidden) {
+            name += "hidden";
+        }
+        name += ")";
+        Action a = new AbstractAction(name, new ColorIcon(f.getColor())) {
 
             @Override
             public void actionPerformed(ActionEvent e) {
@@ -465,16 +476,6 @@
         };
 
         a.setEnabled(true);
-        a.putValue(Action.SMALL_ICON, new ColorIcon(f.getColor()));
-        String name = f.getLines()[0];
-
-        name += " (";
-
-        if (!this.getWidget(f, FigureWidget.class).isVisible()) {
-            name += "hidden";
-        }
-        name += ")";
-        a.putValue(Action.NAME, name);
         return a;
     }
 
@@ -538,8 +539,6 @@
     }
 
     private void smallUpdate(boolean relayout) {
-
-        System.out.println("smallUpdate " + relayout);
         this.updateHiddenNodes(model.getHiddenNodes(), relayout);
         boolean b = this.getUndoRedoEnabled();
         this.setUndoRedoEnabled(false);
@@ -559,8 +558,6 @@
     }
 
     private void relayout(Set<Widget> oldVisibleWidgets) {
-        System.out.println("relayout called with old visible widgets: " + oldVisibleWidgets);
-
         Diagram diagram = getModel().getDiagramToView();
 
         HashSet<Figure> figures = new HashSet<>();
@@ -589,8 +586,6 @@
 
     private void relayoutWithoutLayout(Set<Widget> oldVisibleWidgets) {
 
-        System.out.println("relayout without layout with visible widgets: " + oldVisibleWidgets);
-
         Diagram diagram = getModel().getDiagramToView();
 
         int maxX = -BORDER_SIZE;
@@ -958,8 +953,6 @@
 
     private void updateHiddenNodes(Set<Integer> newHiddenNodes, boolean doRelayout) {
 
-        System.out.println("newHiddenNodes: " + newHiddenNodes);
-
         Diagram diagram = getModel().getDiagramToView();
         assert diagram != null;
 
@@ -1027,7 +1020,7 @@
     private void showFigure(Figure f) {
         HashSet<Integer> newHiddenNodes = new HashSet<>(getModel().getHiddenNodes());
         newHiddenNodes.removeAll(f.getSource().getSourceNodesAsSet());
-        updateHiddenNodes(newHiddenNodes, true);
+        this.model.setHiddenNodes(newHiddenNodes);
     }
 
     public void show(final Figure f) {
@@ -1062,7 +1055,12 @@
 
     public JPopupMenu createPopupMenu() {
         JPopupMenu menu = new JPopupMenu();
-        for (Action a : actions) {
+        
+        Action[] currentActions = actionsWithSelection;
+        if (this.getSelectedObjects().isEmpty()) {
+            currentActions = actions;
+        }
+        for (Action a : currentActions) {
             if (a == null) {
                 menu.addSeparator();
             } else {
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java	Mon Mar 23 16:11:48 2015 +0100
@@ -246,7 +246,7 @@
                         if (last == null) {
                             curColor = Color.green;
                         } else {
-                            if (last.equals(cur)) {
+                            if (last.equals(cur) && last.getProperties().equals(cur.getProperties())) {
                                 if (curColor == Color.black) {
                                     curColor = Color.white;
                                 }
@@ -268,7 +268,6 @@
     }
 
     public void showNot(final Set<Integer> nodes) {
-        System.out.println("Shownot called with " + nodes);
         setHiddenNodes(nodes);
     }
 
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Mon Mar 23 16:11:48 2015 +0100
@@ -178,12 +178,17 @@
             null,
             ZoomInAction.get(ZoomInAction.class),
             ZoomOutAction.get(ZoomOutAction.class),
+        };
+
+        
+        Action[] actionsWithSelection = new Action[]{
+            ExtractAction.get(ExtractAction.class),
+            ShowAllAction.get(HideAction.class),
             null,
             ExpandPredecessorsAction.get(ExpandPredecessorsAction.class),
             ExpandSuccessorsAction.get(ExpandSuccessorsAction.class)
         };
 
-
         initComponents();
 
         ToolbarPool.getDefault().setPreferredIconSize(16);
@@ -201,7 +206,7 @@
         JScrollPane pane = new JScrollPane(rangeSlider, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
         container.add(BorderLayout.CENTER, pane);
 
-        scene = new DiagramScene(actions, rangeSliderModel);
+        scene = new DiagramScene(actions, actionsWithSelection, rangeSliderModel);
         content = new InstanceContent();
         graphContent = new InstanceContent();
         this.associateLookup(new ProxyLookup(new Lookup[]{scene.getLookup(), new AbstractLookup(graphContent), new AbstractLookup(content)}));
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Mon Mar 23 16:11:48 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -62,11 +62,7 @@
 public class FigureWidget extends Widget implements Properties.Provider, PopupMenuProvider, DoubleClickHandler {
 
     public static final boolean VERTICAL_LAYOUT = true;
-    //public static final int MAX_STRING_LENGTH = 20;
     private static final double LABEL_ZOOM_FACTOR = 0.3;
-    private static final double ZOOM_FACTOR = 0.1;
-    private Font font;
-    private Font boldFont;
     private Figure figure;
     private Widget leftWidget;
     private Widget rightWidget;
@@ -74,7 +70,7 @@
     private ArrayList<LabelWidget> labelWidgets;
     private DiagramScene diagramScene;
     private boolean boundary;
-    private Node node;
+    private final Node node;
     private Widget dummyTop;
 
     public void setBoundary(boolean b) {
@@ -89,11 +85,10 @@
         return node;
     }
 
-	@Override
-	public boolean isHitAt(Point localLocation) {
-		return middleWidget.isHitAt(localLocation);
-	}
-    
+    @Override
+    public boolean isHitAt(Point localLocation) {
+        return middleWidget.isHitAt(localLocation);
+    }
 
     public FigureWidget(final Figure f, WidgetAction hoverAction, WidgetAction selectAction, DiagramScene scene, Widget parent) {
 
@@ -103,23 +98,20 @@
         assert this.getScene().getView() != null;
 
         this.figure = f;
-        font = f.getDiagram().getFont();
-        boldFont = f.getDiagram().getFont().deriveFont(Font.BOLD);
         this.setCheckClipping(true);
         this.diagramScene = scene;
         parent.addChild(this);
 
-	Widget outer = new Widget(scene);
-	outer.setBackground(f.getColor());
-	outer.setLayout(LayoutFactory.createOverlayLayout());
-	
+        Widget outer = new Widget(scene);
+        outer.setBackground(f.getColor());
+        outer.setLayout(LayoutFactory.createOverlayLayout());
+
         middleWidget = new Widget(scene);
         middleWidget.setLayout(LayoutFactory.createVerticalFlowLayout(LayoutFactory.SerialAlignment.CENTER, 0));
         middleWidget.setBackground(f.getColor());
         middleWidget.setOpaque(true);
-        //middleWidget.setBorder(BorderFactory.createLineBorder(Color.BLACK));
         middleWidget.getActions().addAction(new DoubleClickAction(this));
-	middleWidget.setCheckClipping(true);
+        middleWidget.setCheckClipping(true);
 
         labelWidgets = new ArrayList<>();
 
@@ -129,7 +121,6 @@
         dummyTop.setMinimumSize(new Dimension(Figure.INSET / 2, 1));
         middleWidget.addChild(dummyTop);
 
-
         for (String cur : strings) {
 
             String displayString = cur;
@@ -138,11 +129,11 @@
             labelWidgets.add(lw);
             middleWidget.addChild(lw);
             lw.setLabel(displayString);
-            lw.setFont(font);
+            lw.setFont(figure.getDiagram().getFont());
             lw.setForeground(Color.BLACK);
             lw.setAlignment(LabelWidget.Alignment.CENTER);
             lw.setVerticalAlignment(LabelWidget.VerticalAlignment.CENTER);
-	    lw.setBorder(BorderFactory.createEmptyBorder());
+            lw.setBorder(BorderFactory.createEmptyBorder());
         }
 
         Widget dummyBottom = new Widget(scene);
@@ -150,7 +141,6 @@
         middleWidget.addChild(dummyBottom);
 
         middleWidget.setPreferredBounds(new Rectangle(0, Figure.SLOT_WIDTH - Figure.OVERLAPPING, f.getWidth(), f.getHeight()));
-	//outer.addChild(middleWidget);
         this.addChild(middleWidget);
 
         // Initialize node for property sheet
@@ -178,49 +168,22 @@
     protected void notifyStateChanged(ObjectState previousState, ObjectState state) {
         super.notifyStateChanged(previousState, state);
 
-        Color borderColor = Color.BLACK;
-	Color innerBorderColor = getFigure().getColor();
-        int thickness = 1;
-        boolean repaint = false;
-        Font f = font;
-        if (state.isSelected() || state.isHighlighted()) {
-            thickness = 2;
-	}
-	if(state.isSelected()) {
-            f = boldFont;
-		innerBorderColor = borderColor;
-        } else {
-	}
-
-        if (state.isHighlighted()) {
-		innerBorderColor = borderColor = Color.BLUE;
-		repaint = true;
-        } else {
-		repaint = true;
-	}
-
-        if (state.isHovered() != previousState.isHovered()) {
-
-		/*
-            if (state.isHovered()) {
-                diagramScene.addAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet());
-            } else {
-                diagramScene.removeAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet());
-            }*/
-            repaint = true;
+        Font font = this.figure.getDiagram().getFont();
+        if (state.isSelected()) {
+            font = this.figure.getDiagram().getBoldFont();
         }
 
-        if (state.isSelected() != previousState.isSelected()) {
-            repaint = true;
+        Color borderColor = Color.BLACK;
+        Color innerBorderColor = getFigure().getColor();
+        if (state.isHighlighted()) {
+            innerBorderColor = borderColor = Color.BLUE;
         }
 
-        if (repaint) {
-            middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1)));
-            for (LabelWidget labelWidget : labelWidgets) {
-                labelWidget.setFont(f);
-            }
-            repaint();
+        middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1)));
+        for (LabelWidget labelWidget : labelWidgets) {
+            labelWidget.setFont(font);
         }
+        repaint();
     }
 
     public String getName() {
@@ -246,7 +209,6 @@
         }
 
         if (diagramScene.getZoomFactor() < LABEL_ZOOM_FACTOR) {
-
             for (LabelWidget labelWidget : labelWidgets) {
                 labelWidget.setVisible(false);
             }
@@ -263,19 +225,15 @@
             getScene().getGraphics().setComposite(oldComposite);
         }
     }
- 
+
     @Override
     public JPopupMenu getPopupMenu(Widget widget, Point point) {
         JPopupMenu menu = diagramScene.createPopupMenu();
         menu.addSeparator();
-
-        JMenu predecessors = new JMenu("Nodes Above");
-        predecessors.addMenuListener(new NeighborMenuListener(predecessors, getFigure(), false));
-        menu.add(predecessors);
-
-        JMenu successors = new JMenu("Nodes Below");
-        successors.addMenuListener(new NeighborMenuListener(successors, getFigure(), true));
-        menu.add(successors);
+        
+        build(menu, getFigure(), this, false, diagramScene);
+        menu.addSeparator();
+        build(menu, getFigure(), this, true, diagramScene);
 
         if (getFigure().getSubgraphs() != null) {
             menu.addSeparator();
@@ -283,7 +241,7 @@
             menu.add(subgraphs);
 
             final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class);
-            for(final InputGraph subgraph : getFigure().getSubgraphs()) {
+            for (final InputGraph subgraph : getFigure().getSubgraphs()) {
                 Action a = new AbstractAction() {
 
                     @Override
@@ -301,10 +259,45 @@
         return menu;
     }
 
+    public static void build(JPopupMenu menu, Figure figure, FigureWidget figureWidget, boolean successors, DiagramScene diagramScene) {
+        Set<Figure> set = figure.getPredecessorSet();
+        if (successors) {
+            set = figure.getSuccessorSet();
+        }
+
+        boolean first = true;
+        for (Figure f : set) {
+            if (f == figure) {
+                continue;
+            }
+
+            if (first) {
+                first = false;
+            } else {
+                menu.addSeparator();
+            }
+
+            Action go = diagramScene.createGotoAction(f);
+            menu.add(go);
+
+            JMenu preds = new JMenu("Nodes Above");
+            preds.addMenuListener(figureWidget.new NeighborMenuListener(preds, f, false));
+            menu.add(preds);
+
+            JMenu succs = new JMenu("Nodes Below");
+            succs.addMenuListener(figureWidget.new NeighborMenuListener(succs, f, true));
+            menu.add(succs);
+        }
+
+        if (figure.getPredecessorSet().isEmpty() && figure.getSuccessorSet().isEmpty()) {
+            menu.add("(none)");
+        }
+    }
+
     /**
      * Builds the submenu for a figure's neighbors on demand.
      */
-    private class NeighborMenuListener implements MenuListener {
+    public class NeighborMenuListener implements MenuListener {
 
         private final JMenu menu;
         private final Figure figure;
@@ -323,38 +316,7 @@
                 return;
             }
 
-            Set<Figure> set = figure.getPredecessorSet();
-            if (successors) {
-                set = figure.getSuccessorSet();
-            }
-
-            boolean first = true;
-            for (Figure f : set) {
-                if (f == figure) {
-                    continue;
-                }
-
-                if (first) {
-                    first = false;
-                } else {
-                    menu.addSeparator();
-                }
-
-                Action go = diagramScene.createGotoAction(f);
-                menu.add(go);
-
-                JMenu preds = new JMenu("Nodes Above");
-                preds.addMenuListener(new NeighborMenuListener(preds, f, false));
-                menu.add(preds);
-
-                JMenu succs = new JMenu("Nodes Below");
-                succs.addMenuListener(new NeighborMenuListener(succs, f, true));
-                menu.add(succs);
-            }
-
-            if (menu.getItemCount() == 0) {
-                menu.add("(none)");
-            }
+            build(menu.getPopupMenu(), figure, FigureWidget.this, successors, diagramScene);
         }
 
         @Override
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java	Mon Mar 23 16:11:48 2015 +0100
@@ -109,7 +109,6 @@
         if (connections.size() > 0) {
             color = connections.get(0).getColor();
         }
-
         this.setToolTipText("<HTML>" + generateToolTipText(this.connections) + "</HTML>");
 
         this.setCheckClipping(true);
@@ -203,7 +202,7 @@
         g.drawLine(from.x, from.y, to.x, to.y);
 
         boolean sameFrom = false;
-        boolean sameTo = successors.size() == 0;
+        boolean sameTo = successors.isEmpty();
         for (LineWidget w : successors) {
             if (w.getFrom().equals(getTo())) {
                 sameTo = true;
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java	Mon Mar 23 16:11:48 2015 +0100
@@ -41,12 +41,9 @@
     public OutputSlotWidget(OutputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) {
         super(slot, scene, parent, fw);
         outputSlot = slot;
-        //init();
-        //getFigureWidget().getRightWidget().addChild(this);
         Point p = outputSlot.getRelativePosition();
         p.y += getSlot().getFigure().getHeight() - Figure.SLOT_START;
         p.x -= this.calculateClientArea().width / 2;
-        //p.x += this.calculateClientArea().width / 2;
         this.setPreferredLocation(p);
     }
 
@@ -56,21 +53,9 @@
 
     @Override
     protected int calculateSlotWidth() {
-        
         List<OutputSlot> slots = getSlot().getFigure().getOutputSlots();
         assert slots.contains(getSlot());
         return calculateWidth(slots.size());
         
     }
-    /*
-    protected Point calculateRelativeLocation() {
-        if (getFigureWidget().getBounds() == null) {
-            return new Point(0, 0);
-        }
-
-        double x = this.getFigureWidget().getBounds().width;
-        List<OutputSlot> slots = outputSlot.getFigure().getOutputSlots();
-        assert slots.contains(outputSlot);
-        return new Point((int) x, (int) (calculateRelativeY(slots.size(), slots.indexOf(outputSlot))));
-    }*/
 }
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java	Mon Mar 23 16:11:48 2015 +0100
@@ -59,17 +59,16 @@
         this.setToolTipText("<HTML>" + slot.getToolTipText() + "</HTML>");
         this.setCheckClipping(true);
         parent.addChild(this);
-        
+
         //this.setPreferredBounds(this.calculateClientArea());
     }
-    
-    
+
     @Override
     protected void notifyStateChanged(ObjectState previousState, ObjectState state) {
         super.notifyStateChanged(previousState, state);
-	repaint();
+        repaint();
     }
-    
+
     public Slot getSlot() {
         return slot;
     }
@@ -86,58 +85,59 @@
         }
 
         Graphics2D g = this.getGraphics();
-       // g.setColor(Color.DARK_GRAY);
+        // g.setColor(Color.DARK_GRAY);
         int w = this.getBounds().width;
         int h = this.getBounds().height;
 
-        if(getSlot().getSource().getSourceNodes().size() > 0) {
+        if (getSlot().getSource().getSourceNodes().size() > 0) {
             final int SMALLER = 0;
             g.setColor(getSlot().getColor());
 
             int FONT_OFFSET = 2;
-            
+
             int s = h - SMALLER;
             int rectW = s;
-            
+
             Font font = this.getSlot().getFigure().getDiagram().getSlotFont();
-            if(this.getState().isSelected()) {
+            if (this.getState().isSelected()) {
                 font = font.deriveFont(Font.BOLD);
             }
-            
+
             if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0) {
                 g.setFont(font);
                 Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g);
-                rectW = (int)r1.getWidth() + FONT_OFFSET * 2;
+                rectW = (int) r1.getWidth() + FONT_OFFSET * 2;
             }
-            g.fillRect(w/2 - rectW/2, 0, rectW-1, s-1);
-            
-            if(this.getState().isHighlighted()) {
+            g.fillRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1);
+
+            if (this.getState().isHighlighted()) {
                 g.setColor(Color.BLUE);
             } else {
                 g.setColor(Color.BLACK);
             }
-            g.drawRect(w/2 - rectW/2, 0, rectW-1, s-1);
-            
-            
+            g.drawRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1);
+
             if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0 && getScene().getZoomFactor() >= TEXT_ZOOM_FACTOR) {
                 Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g);
-                g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent()-1);//(int) (r1.getHeight()));
+                g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent() - 1);//(int) (r1.getHeight()));
             }
-            
+
         } else {
 
-            if(this.getState().isHighlighted()) {
-                g.setColor(Color.BLUE);
+            if (this.getSlot().getConnections().isEmpty()) {
+                if (this.getState().isHighlighted()) {
+                    g.setColor(Color.BLUE);
+                } else {
+                    g.setColor(Color.BLACK);
+                }
+                int r = 2;
+                if (slot instanceof OutputSlot) {
+                    g.fillOval(w / 2 - r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2 * r, 2 * r);
+                } else {
+                    g.fillOval(w / 2 - r, Figure.SLOT_START - r, 2 * r, 2 * r);
+                }
             } else {
-                g.setColor(Color.BLACK);
-            }
-            int r = 2;
-            if (slot instanceof OutputSlot) {
-                g.fillOval(w/2-r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2*r, 2*r);
-                //g.fillArc(w / 2 - r, -r, 2*r, 2*r, 180, 180);
-            } else {
-                g.fillOval(w/2-r, Figure.SLOT_START - r, 2*r, 2*r);
-                //g.fillArc(w / 2 - r, h - r, 2*r, 2*r, 0, 180);
+                // Do not paint a slot with connections.
             }
         }
     }
@@ -146,9 +146,9 @@
     protected Rectangle calculateClientArea() {
         return new Rectangle(0, 0, slot.getWidth(), Figure.SLOT_WIDTH);
     }
- 
+
     protected abstract int calculateSlotWidth();
-    
+
     protected int calculateWidth(int count) {
         return getFigureWidget().getFigure().getWidth() / count;
     }
@@ -158,19 +158,19 @@
         Set<Integer> hiddenNodes = new HashSet<>(diagramScene.getModel().getHiddenNodes());
         if (diagramScene.isAllVisible()) {
             hiddenNodes = new HashSet<>(diagramScene.getModel().getGraphToView().getGroup().getAllNodes());
-        } 
+        }
 
         boolean progress = false;
-        for(Figure f : diagramScene.getModel().getDiagramToView().getFigures()) {
-            for(Slot s : f.getSlots()) {
-                if(DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) {
+        for (Figure f : diagramScene.getModel().getDiagramToView().getFigures()) {
+            for (Slot s : f.getSlots()) {
+                if (DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) {
                     progress = true;
                     hiddenNodes.removeAll(f.getSource().getSourceNodesAsSet());
                 }
             }
         }
 
-        if(progress) {
+        if (progress) {
             this.diagramScene.getModel().showNot(hiddenNodes);
         }
     }
--- a/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties	Mon Mar 23 16:11:48 2015 +0100
@@ -1,114 +1,8 @@
+branding.token=idealgraphvisualizer
 cluster.path=\
     ${nbplatform.active.dir}/ide:\
     ${nbplatform.active.dir}/platform
-disabled.modules=\
-    org.apache.commons.codec,\
-    org.apache.commons.httpclient,\
-    org.apache.commons.io,\
-    org.apache.commons.lang,\
-    org.apache.ws.commons.util,\
-    org.apache.xmlrpc,\
-    org.eclipse.core.contenttype,\
-    org.eclipse.core.jobs,\
-    org.eclipse.core.net,\
-    org.eclipse.core.runtime,\
-    org.eclipse.core.runtime.compatibility.auth,\
-    org.eclipse.equinox.app,\
-    org.eclipse.equinox.common,\
-    org.eclipse.equinox.preferences,\
-    org.eclipse.equinox.registry,\
-    org.eclipse.equinox.security,\
-    org.eclipse.jgit,\
-    org.eclipse.mylyn.bugzilla.core,\
-    org.eclipse.mylyn.commons.core,\
-    org.eclipse.mylyn.commons.net,\
-    org.eclipse.mylyn.commons.repositories.core,\
-    org.eclipse.mylyn.commons.xmlrpc,\
-    org.eclipse.mylyn.tasks.core,\
-    org.eclipse.mylyn.wikitext.confluence.core,\
-    org.eclipse.mylyn.wikitext.core,\
-    org.eclipse.mylyn.wikitext.textile.core,\
-    org.netbeans.api.debugger,\
-    org.netbeans.core.browser,\
-    org.netbeans.core.browser.webview,\
-    org.netbeans.libs.commons_net,\
-    org.netbeans.libs.git,\
-    org.netbeans.libs.ini4j,\
-    org.netbeans.libs.jsch.agentproxy,\
-    org.netbeans.libs.json_simple,\
-    org.netbeans.libs.smack,\
-    org.netbeans.libs.svnClientAdapter,\
-    org.netbeans.libs.svnClientAdapter.javahl,\
-    org.netbeans.libs.svnClientAdapter.svnkit,\
-    org.netbeans.libs.swingx,\
-    org.netbeans.modules.bugtracking,\
-    org.netbeans.modules.bugtracking.bridge,\
-    org.netbeans.modules.bugzilla,\
-    org.netbeans.modules.code.analysis,\
-    org.netbeans.modules.css.prep,\
-    org.netbeans.modules.db,\
-    org.netbeans.modules.db.core,\
-    org.netbeans.modules.db.dataview,\
-    org.netbeans.modules.db.drivers,\
-    org.netbeans.modules.db.kit,\
-    org.netbeans.modules.db.metadata.model,\
-    org.netbeans.modules.db.mysql,\
-    org.netbeans.modules.db.sql.editor,\
-    org.netbeans.modules.db.sql.visualeditor,\
-    org.netbeans.modules.dbapi,\
-    org.netbeans.modules.derby,\
-    org.netbeans.modules.editor.global.format,\
-    org.netbeans.modules.editor.indent.project,\
-    org.netbeans.modules.extexecution.impl,\
-    org.netbeans.modules.git,\
-    org.netbeans.modules.gototest,\
-    org.netbeans.modules.gsf.codecoverage,\
-    org.netbeans.modules.gsf.testrunner,\
-    org.netbeans.modules.html.angular,\
-    org.netbeans.modules.html.knockout,\
-    org.netbeans.modules.hudson,\
-    org.netbeans.modules.hudson.git,\
-    org.netbeans.modules.hudson.mercurial,\
-    org.netbeans.modules.hudson.subversion,\
-    org.netbeans.modules.hudson.tasklist,\
-    org.netbeans.modules.hudson.ui,\
-    org.netbeans.modules.jellytools.ide,\
-    org.netbeans.modules.languages,\
-    org.netbeans.modules.lexer.nbbridge,\
-    org.netbeans.modules.localhistory,\
-    org.netbeans.modules.mercurial,\
-    org.netbeans.modules.mylyn.util,\
-    org.netbeans.modules.notifications,\
-    org.netbeans.modules.parsing.ui,\
-    org.netbeans.modules.project.ant,\
-    org.netbeans.modules.projectui.buildmenu,\
-    org.netbeans.modules.properties.syntax,\
-    org.netbeans.modules.schema2beans,\
-    org.netbeans.modules.server,\
-    org.netbeans.modules.spellchecker,\
-    org.netbeans.modules.spellchecker.apimodule,\
-    org.netbeans.modules.spellchecker.bindings.htmlxml,\
-    org.netbeans.modules.spellchecker.bindings.properties,\
-    org.netbeans.modules.spellchecker.dictionary_en,\
-    org.netbeans.modules.spellchecker.kit,\
-    org.netbeans.modules.subversion,\
-    org.netbeans.modules.swing.validation,\
-    org.netbeans.modules.target.iterator,\
-    org.netbeans.modules.team.commons,\
-    org.netbeans.modules.team.ide,\
-    org.netbeans.modules.utilities.project,\
-    org.netbeans.modules.versioning,\
-    org.netbeans.modules.versioning.core,\
-    org.netbeans.modules.versioning.indexingbridge,\
-    org.netbeans.modules.versioning.masterfs,\
-    org.netbeans.modules.versioning.system.cvss.installer,\
-    org.netbeans.modules.versioning.ui,\
-    org.netbeans.modules.versioning.util,\
-    org.netbeans.modules.web.webkit.debugging,\
-    org.netbeans.modules.xml.multiview,\
-    org.netbeans.spi.debugger.ui,\
-    org.netbeans.spi.viewmodel,\
-    org.openidex.util
+disabled.modules=
 nbplatform.active.dir=${suite.dir}/nbplatform
 nbplatform.default.netbeans.dest.dir=${suite.dir}/nbplatform
 nbplatform.default.harness.dir=${nbplatform.default.netbeans.dest.dir}/harness
--- a/src/share/tools/IdealGraphVisualizer/nbproject/project.properties	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/nbproject/project.properties	Mon Mar 23 16:11:48 2015 +0100
@@ -1,44 +1,50 @@
-app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif
-app.name=idealgraphvisualizer
-app.title=IdealGraphVisualizer
-branding.token=${app.name}
-modules=\
-    ${project.com.sun.hotspot.igv.graph}:\
-    ${project.com.sun.hotspot.igv.coordinator}:\
-    ${project.com.sun.hotspot.igv.filter}:\
-    ${project.com.sun.hotspot.igv.hierarchicallayout}:\
-    ${project.com.sun.hotspot.igv.layout}:\
-    ${project.com.sun.hotspot.igv.data}:\
-    ${project.com.sun.hotspot.igv.view}:\
-    ${project.com.sun.hotspot.igv.bytecodes}:\
-    ${project.com.sun.hotspot.igv.difference}:\
-    ${project.com.sun.hotspot.igv.settings}:\
-    ${project.com.sun.hotspot.igv.util}:\
-    ${project.com.sun.hotspot.igv.svg}:\
-    ${project.com.sun.hotspot.connection}:\
-    ${project.com.sun.hotspot.igv.servercompilerscheduler}:\
-    ${project.com.sun.hotspot.igv.filterwindow}:\
-    ${project.com.sun.hotspot.igv.selectioncoordinator}:\
-    ${project.com.sun.hotspot.igv.graal}
-project.com.sun.hotspot.connection=NetworkConnection
-project.com.sun.hotspot.igv.bytecodes=Bytecodes
-project.com.sun.hotspot.igv.coordinator=Coordinator
-project.com.sun.hotspot.igv.data=Data
-project.com.sun.hotspot.igv.difference=Difference
-project.com.sun.hotspot.igv.filter=Filter
-project.com.sun.hotspot.igv.filterwindow=FilterWindow
-project.com.sun.hotspot.igv.graal=Graal
-project.com.sun.hotspot.igv.graph=Graph
-project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout
-project.com.sun.hotspot.igv.layout=Layout
-project.com.sun.hotspot.igv.selectioncoordinator=SelectionCoordinator
-project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler
-project.com.sun.hotspot.igv.settings=Settings
-project.com.sun.hotspot.igv.svg=BatikSVGProxy
-project.com.sun.hotspot.igv.view=View
-project.com.sun.hotspot.igv.util=Util
-
-# Disable assertions for RequestProcessor to prevent annoying messages in case
-# of multiple SceneAnimator update tasks in the default RequestProcessor.
-run.args.extra = -J-server -J-da:org.openide.util.RequestProcessor -J-Xms2g -J-Xmx8g -J-Djava.lang.Integer.IntegerCache.high=20000
-debug.args.extra = -J-server -J-da:org.openide.util.RequestProcessor
+app.icon=branding/core/core.jar/org/netbeans/core/startup/frame48.gif
+app.name=${branding.token}
+app.title=IdealGraphVisualizer
+auxiliary.org-netbeans-modules-apisupport-installer.license-type=no
+auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false
+auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=true
+auxiliary.org-netbeans-modules-apisupport-installer.os-solaris=false
+auxiliary.org-netbeans-modules-apisupport-installer.os-windows=false
+auxiliary.org-netbeans-modules-apisupport-installer.pack200-enabled=false
+auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml
+modules=\
+    ${project.com.sun.hotspot.igv.graph}:\
+    ${project.com.sun.hotspot.igv.coordinator}:\
+    ${project.com.sun.hotspot.igv.filter}:\
+    ${project.com.sun.hotspot.igv.hierarchicallayout}:\
+    ${project.com.sun.hotspot.igv.layout}:\
+    ${project.com.sun.hotspot.igv.data}:\
+    ${project.com.sun.hotspot.igv.view}:\
+    ${project.com.sun.hotspot.igv.bytecodes}:\
+    ${project.com.sun.hotspot.igv.difference}:\
+    ${project.com.sun.hotspot.igv.settings}:\
+    ${project.com.sun.hotspot.igv.util}:\
+    ${project.com.sun.hotspot.igv.svg}:\
+    ${project.com.sun.hotspot.connection}:\
+    ${project.com.sun.hotspot.igv.servercompilerscheduler}:\
+    ${project.com.sun.hotspot.igv.filterwindow}:\
+    ${project.com.sun.hotspot.igv.selectioncoordinator}:\
+    ${project.com.sun.hotspot.igv.graal}
+project.com.sun.hotspot.connection=NetworkConnection
+project.com.sun.hotspot.igv.bytecodes=Bytecodes
+project.com.sun.hotspot.igv.coordinator=Coordinator
+project.com.sun.hotspot.igv.data=Data
+project.com.sun.hotspot.igv.difference=Difference
+project.com.sun.hotspot.igv.filter=Filter
+project.com.sun.hotspot.igv.filterwindow=FilterWindow
+project.com.sun.hotspot.igv.graal=Graal
+project.com.sun.hotspot.igv.graph=Graph
+project.com.sun.hotspot.igv.hierarchicallayout=HierarchicalLayout
+project.com.sun.hotspot.igv.layout=Layout
+project.com.sun.hotspot.igv.selectioncoordinator=SelectionCoordinator
+project.com.sun.hotspot.igv.servercompilerscheduler=ServerCompiler
+project.com.sun.hotspot.igv.settings=Settings
+project.com.sun.hotspot.igv.svg=BatikSVGProxy
+project.com.sun.hotspot.igv.view=View
+project.com.sun.hotspot.igv.util=Util
+
+# Disable assertions for RequestProcessor to prevent annoying messages in case
+# of multiple SceneAnimator update tasks in the default RequestProcessor.
+run.args.extra = -J-server -J-da:org.openide.util.RequestProcessor -J-Xms2g -J-Xmx8g -J-Djava.lang.Integer.IntegerCache.high=20000
+debug.args.extra = -J-server -J-da:org.openide.util.RequestProcessor
--- a/src/share/vm/runtime/deoptimization.cpp	Mon Mar 23 15:58:36 2015 +0100
+++ b/src/share/vm/runtime/deoptimization.cpp	Mon Mar 23 16:11:48 2015 +0100
@@ -1547,6 +1547,7 @@
       if (TraceDeoptimization) {  // make noise on the tty
         tty->print("Uncommon trap occurred in");
         nm->method()->print_short_name(tty);
+        tty->print(" compiler=%s compile_id=%d", nm->compiler() == NULL ? "" : nm->compiler()->name(), nm->compile_id());
 #ifdef GRAAL
         oop installedCode = nm->graal_installed_code();
         if (installedCode != NULL) {