changeset 20010:3819bcdde898

Merge
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Mon, 23 Mar 2015 10:27:17 -0700
parents 426e45c75771 (current diff) 220c494e5088 (diff)
children 30769a7dc619
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.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 91 files changed, 1768 insertions(+), 1258 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/NamedLocationIdentity.java	Mon Mar 23 10:27:17 2015 -0700
@@ -88,7 +88,7 @@
 
     @Override
     public String toString() {
-        return name + (isImmutable() ? ":immutable" : ":mutable");
+        return name + (isImmutable() ? ":final" : "");
     }
 
     /**
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCAssembler.java	Mon Mar 23 10:27:17 2015 -0700
@@ -1741,4 +1741,20 @@
     public void casxa(Register rs1, Register rs2, Register rd, Asi asi) {
         ld(Casxa, new SPARCAddress(rs1, rs2), rd, asi);
     }
+
+    @Override
+    public InstructionCounter getInstructionCounter() {
+        return new SPARCInstructionCounter(this);
+    }
+
+    public void patchAddImmediate(int position, int simm13) {
+        int inst = getInt(position);
+        assert SPARCAssembler.isSimm13(simm13) : simm13;
+        assert (inst >>> 30) == 0b10 : String.format("0x%x", inst);
+        assert ((inst >>> 18) & 0b11_1111) == 0 : String.format("0x%x", inst);
+        assert (inst & (1 << 13)) != 0 : String.format("0x%x", inst);
+        inst = inst & (~((1 << 13) - 1));
+        inst |= simm13 & ((1 << 12) - 1);
+        emitInt(inst, position);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCInstructionCounter.java	Mon Mar 23 10:27:17 2015 -0700
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.asm.sparc;
+
+import java.util.*;
+
+import com.oracle.graal.asm.Assembler.InstructionCounter;
+
+public class SPARCInstructionCounter implements InstructionCounter {
+    // Use a treemap to keep the order in the output
+    private static final TreeMap<String, SPARCInstructionMatch> INSTRUCTION_MATCHER = new TreeMap<>();
+    static {
+        // @formatter:off
+        INSTRUCTION_MATCHER.put("nop", new SPARCInstructionMatch(0xFFFF_FFFF, 0x0100_0000));
+        INSTRUCTION_MATCHER.put("st", new OP3LowBitsMatcher(0b11, 0x4, 0x5, 0x6, 0x7, 0xe, 0xf));
+        INSTRUCTION_MATCHER.put("ld", new OP3LowBitsMatcher(0b11, 0x0, 0x1, 0x2, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd));
+        INSTRUCTION_MATCHER.put("all", new SPARCInstructionMatch(0x0, 0x0));
+        // @formatter:on
+    }
+    private final SPARCAssembler asm;
+
+    public SPARCInstructionCounter(SPARCAssembler asm) {
+        super();
+        this.asm = asm;
+    }
+
+    @Override
+    public int[] countInstructions(String[] instructionTypes, int beginPc, int endPc) {
+        SPARCInstructionMatch[] matchers = new SPARCInstructionMatch[instructionTypes.length];
+        for (int i = 0; i < instructionTypes.length; i++) {
+            String typeName = instructionTypes[i];
+            matchers[i] = INSTRUCTION_MATCHER.get(typeName);
+            if (matchers[i] == null) {
+                throw new IllegalArgumentException(String.format("Unknown instruction class %s, supported types are: %s", typeName, INSTRUCTION_MATCHER.keySet()));
+            }
+        }
+        return countBetween(matchers, beginPc, endPc);
+    }
+
+    private int[] countBetween(SPARCInstructionMatch[] matchers, int startPc, int endPc) {
+        int[] counts = new int[matchers.length];
+        for (int p = startPc; p < endPc; p += 4) {
+            int instr = asm.getInt(p);
+            for (int i = 0; i < matchers.length; i++) {
+                SPARCInstructionMatch matcher = matchers[i];
+                if (matcher.matches(instr)) {
+                    counts[i]++;
+                }
+            }
+        }
+        return counts;
+    }
+
+    @Override
+    public String[] getSupportedInstructionTypes() {
+        return INSTRUCTION_MATCHER.keySet().toArray(new String[0]);
+    }
+
+    /**
+     * Tests the lower 3 bits of the op3 field.
+     */
+    private static class OP3LowBitsMatcher extends SPARCInstructionMatch {
+        private final int[] op3b03;
+        private final int op;
+
+        public OP3LowBitsMatcher(int op, int... op3b03) {
+            super(0, 0);
+            this.op = op;
+            this.op3b03 = op3b03;
+        }
+
+        @Override
+        public boolean matches(int instruction) {
+            if (instruction >>> 30 != op) {
+                return false;
+            }
+            int op3lo = (instruction >> 19) & ((1 << 4) - 1);
+            for (int op3Part : op3b03) {
+                if (op3Part == op3lo) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    private static class SPARCInstructionMatch {
+        private final int mask;
+        private final int[] patterns;
+
+        public SPARCInstructionMatch(int mask, int... patterns) {
+            super();
+            this.mask = mask;
+            this.patterns = patterns;
+        }
+
+        public boolean matches(int instruction) {
+            for (int pattern : patterns) {
+                if ((instruction & mask) == pattern) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+}
--- a/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.asm/src/com/oracle/graal/asm/Assembler.java	Mon Mar 23 10:27:17 2015 -0700
@@ -213,6 +213,10 @@
         return hint;
     }
 
+    public InstructionCounter getInstructionCounter() {
+        throw new UnsupportedOperationException("Instruction counter is not implemented for " + this);
+    }
+
     public static class LabelHint {
         private Label label;
         private int forPosition;
@@ -242,4 +246,14 @@
             return capturedTarget >= 0;
         }
     }
+
+    /**
+     * Instruction counter class which gives the user of the assembler to count different kinds of
+     * instructions in the generated assembler code.
+     */
+    public interface InstructionCounter {
+        String[] getSupportedInstructionTypes();
+
+        int[] countInstructions(String[] instructionTypes, int beginPc, int endPc);
+    }
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Mar 23 10:27:17 2015 -0700
@@ -320,7 +320,14 @@
                 throw Debug.handle(e);
             }
             FrameMapBuilder frameMapBuilder = backend.newFrameMapBuilder(registerConfig);
-            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(lir, frameMapBuilder, graph.method(), stub);
+            String compilationUnitName;
+            ResolvedJavaMethod method = graph.method();
+            if (method == null) {
+                compilationUnitName = "<unknown>";
+            } else {
+                compilationUnitName = method.format("%H.%n(%p)");
+            }
+            LIRGenerationResult lirGenRes = backend.newLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, graph.method(), stub);
             LIRGeneratorTool lirGen = backend.newLIRGenerator(cc, lirGenRes);
             NodeLIRBuilderTool nodeLirGen = backend.newNodeLIRBuilder(graph, lirGen);
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Mon Mar 23 10:27:17 2015 -0700
@@ -78,7 +78,7 @@
 
     public abstract LIRGeneratorTool newLIRGenerator(CallingConvention cc, LIRGenerationResult lirGenRes);
 
-    public abstract LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub);
+    public abstract LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub);
 
     public abstract NodeLIRBuilderTool newNodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool lirGen);
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackend.java	Mon Mar 23 10:27:17 2015 -0700
@@ -78,8 +78,8 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
-        return new AMD64HotSpotLIRGenerationResult(lir, frameMapBuilder, stub);
+    public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
+        return new AMD64HotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub);
     }
 
     @Override
@@ -254,6 +254,9 @@
 
         // Emit the suffix
         emitCodeSuffix(installedCodeOwner, crb, asm, frameMap);
+
+        // Profile assembler instructions
+        profileInstructions(lir, crb);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotCounterOp.java	Mon Mar 23 10:27:17 2015 -0700
@@ -65,16 +65,16 @@
 
         // load counters array
         masm.movptr(countersArrayReg, countersArrayAddr);
-
-        forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+        CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement);
+        forEachCounter(emitProcedure, target);
 
         // restore scratch register
         masm.movq(scratch, (AMD64Address) crb.asAddress(backupSlot));
     }
 
-    private void emitIncrement(AMD64MacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) {
+    private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value increment, int displacement) {
         // address for counter value
-        AMD64Address counterAddr = new AMD64Address(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment)));
+        AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement);
         // increment counter (in memory)
         if (isConstant(increment)) {
             masm.incrementl(counterAddr, asInt(asConstant(increment)));
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotLIRGenerationResult.java	Mon Mar 23 10:27:17 2015 -0700
@@ -48,8 +48,8 @@
      */
     private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = CollectionsFactory.newMap();
 
-    public AMD64HotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
-        super(lir, frameMapBuilder);
+    public AMD64HotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
+        super(compilationUnitName, lir, frameMapBuilder);
         this.stub = stub;
     }
 
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Mon Mar 23 10:27:17 2015 -0700
@@ -80,8 +80,8 @@
     }
 
     @Override
-    public LIRGenerationResult newLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
-        return new SPARCHotSpotLIRGenerationResult(lir, frameMapBuilder, stub);
+    public LIRGenerationResult newLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, ResolvedJavaMethod method, Object stub) {
+        return new SPARCHotSpotLIRGenerationResult(compilationUnitName, lir, frameMapBuilder, stub);
     }
 
     @Override
@@ -247,6 +247,8 @@
             crb.emit(lir);
         } while (i++ < 1);
 
+        profileInstructions(lir, crb);
+
         HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
         HotSpotForeignCallsProvider foreignCalls = getProviders().getForeignCalls();
         if (!frameContext.isStub) {
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Mon Mar 23 10:27:17 2015 -0700
@@ -23,11 +23,14 @@
 package com.oracle.graal.hotspot.sparc;
 
 import static com.oracle.graal.api.code.ValueUtil.*;
+import static com.oracle.graal.asm.sparc.SPARCAssembler.*;
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
@@ -37,12 +40,16 @@
 public class SPARCHotSpotCounterOp extends HotSpotCounterOp {
     public static final LIRInstructionClass<SPARCHotSpotCounterOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class);
 
+    private int[] counterPatchOffsets;
+
     public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
         super(TYPE, name, group, increment, registers, config);
+        this.counterPatchOffsets = new int[1];
     }
 
     public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
         super(TYPE, names, groups, increments, registers, config);
+        this.counterPatchOffsets = new int[names.length];
     }
 
     @Override
@@ -57,19 +64,17 @@
 
             // load counters array
             masm.ldx(countersArrayAddr, countersArrayReg);
-
-            forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+            IncrementEmitter emitter = new IncrementEmitter(countersArrayReg, masm);
+            forEachCounter(emitter, target);
         }
     }
 
-    private void emitIncrement(SPARCMacroAssembler masm, TargetDescription target, Register countersArrayReg, String name, String group, Value increment) {
-        // address for counter
-        SPARCAddress counterAddr = new SPARCAddress(countersArrayReg, getDisplacementForLongIndex(target, getIndex(name, group, increment)));
-
+    private void emitIncrement(int counterIndex, SPARCMacroAssembler masm, SPARCAddress counterAddr, Value increment) {
         try (ScratchRegister scratch = masm.getScratchRegister()) {
             Register counterReg = scratch.getRegister();
             // load counter value
             masm.ldx(counterAddr, counterReg);
+            counterPatchOffsets[counterIndex] = masm.position();
             // increment counter
             if (isConstant(increment)) {
                 masm.add(counterReg, asInt(asConstant(increment)), counterReg);
@@ -80,4 +85,53 @@
             masm.stx(counterReg, counterAddr);
         }
     }
+
+    /**
+     * Patches the increment value in the instruction emitted by the
+     * {@link #emitIncrement(int, SPARCMacroAssembler, SPARCAddress, Value)} method. This method is
+     * used if patching is needed after assembly.
+     *
+     * @param asm
+     * @param increment
+     */
+    @Override
+    public void patchCounterIncrement(Assembler asm, int[] increment) {
+        for (int i = 0; i < increment.length; i++) {
+            int inst = counterPatchOffsets[i];
+            ((SPARCAssembler) asm).patchAddImmediate(inst, increment[i]);
+        }
+    }
+
+    public int[] getCounterPatchOffsets() {
+        return counterPatchOffsets;
+    }
+
+    private class IncrementEmitter implements CounterProcedure {
+        private int lastDisplacement = 0;
+        private final Register countersArrayReg;
+        private final SPARCMacroAssembler masm;
+
+        public IncrementEmitter(Register countersArrayReg, SPARCMacroAssembler masm) {
+            super();
+            this.countersArrayReg = countersArrayReg;
+            this.masm = masm;
+        }
+
+        public void apply(int counterIndex, Value increment, int displacement) {
+            SPARCAddress counterAddr;
+            int relativeDisplacement = displacement - lastDisplacement;
+            if (isSimm13(relativeDisplacement)) { // Displacement fits into ld instruction
+                counterAddr = new SPARCAddress(countersArrayReg, relativeDisplacement);
+            } else {
+                try (ScratchRegister scratch = masm.getScratchRegister()) {
+                    Register tempOffsetRegister = scratch.getRegister();
+                    new Setx(relativeDisplacement, tempOffsetRegister, false).emit(masm);
+                    masm.add(countersArrayReg, tempOffsetRegister, countersArrayReg);
+                }
+                lastDisplacement = displacement;
+                counterAddr = new SPARCAddress(countersArrayReg, 0);
+            }
+            emitIncrement(counterIndex, masm, counterAddr, increment);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerationResult.java	Mon Mar 23 10:27:17 2015 -0700
@@ -47,8 +47,8 @@
      */
     private Map<LIRFrameState, SaveRegistersOp> calleeSaveInfo = new HashMap<>();
 
-    public SPARCHotSpotLIRGenerationResult(LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
-        super(lir, frameMapBuilder);
+    public SPARCHotSpotLIRGenerationResult(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder, Object stub) {
+        super(compilationUnitName, lir, frameMapBuilder);
         this.stub = stub;
     }
 
@@ -67,5 +67,4 @@
     Map<LIRFrameState, SaveRegistersOp> getCalleeSaveInfo() {
         return calleeSaveInfo;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/HotSpotCryptoSubstitutionTest.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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/HotSpotBackend.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotBackend.java	Mon Mar 23 10:27:17 2015 -0700
@@ -40,6 +40,7 @@
 import com.oracle.graal.lir.LIRInstruction.OperandMode;
 import com.oracle.graal.lir.StandardOp.LabelOp;
 import com.oracle.graal.lir.StandardOp.SaveRegistersOp;
+import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.framemap.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.options.*;
@@ -55,6 +56,9 @@
         // @formatter:off
         @Option(help = "Use Graal stubs instead of HotSpot stubs where possible")
         public static final OptionValue<Boolean> PreferGraalStubs = new OptionValue<>(false);
+        @Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." +
+                        " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
+        public static final OptionValue<String> ASMInstructionProfiling = new OptionValue<>(null);
         // @formatter:on
     }
 
@@ -235,4 +239,10 @@
     public DisassemblerProvider getDisassembler() {
         return getProviders().getDisassembler();
     }
+
+    protected void profileInstructions(LIR lir, CompilationResultBuilder crb) {
+        if (HotSpotBackend.Options.ASMInstructionProfiling.getValue() != null) {
+            HotSpotInstructionProfiling.countInstructions(lir, crb.asm);
+        }
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotCounterOp.java	Mon Mar 23 10:27:17 2015 -0700
@@ -24,6 +24,8 @@
 
 import static com.oracle.graal.api.code.ValueUtil.*;
 
+import java.util.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
@@ -67,12 +69,42 @@
     }
 
     protected interface CounterProcedure {
-        void apply(String name, String group, Value increment);
+        /**
+         * Lambda interface for iterating over counters declared in this op.
+         *
+         * @param counterIndex Index in this CounterOp object.
+         * @param increment Value for increment
+         * @param displacement Displacement in bytes in the counter array
+         */
+        void apply(int counterIndex, Value increment, int displacement);
     }
 
-    protected void forEachCounter(CounterProcedure proc) {
-        for (int i = 0; i < names.length; i++) {
-            proc.apply(names[i], groups[i], increments[i]);
+    /**
+     * Calls the {@link CounterProcedure} for each counter in ascending order of their displacement
+     * in the counter array.
+     *
+     * @param proc The procedure to be called
+     * @param target Target architecture (used to calculate the array displacements)
+     */
+    protected void forEachCounter(CounterProcedure proc, TargetDescription target) {
+        if (names.length == 1) { // fast path
+            int arrayIndex = getIndex(names[0], groups[0], increments[0]);
+            int displacement = getDisplacementForLongIndex(target, arrayIndex);
+            proc.apply(0, increments[0], displacement);
+        } else { // Slow path with sort by displacements ascending
+            int[] displacements = new int[names.length];
+            HashMap<Integer, Integer> offsetMap = new HashMap<>(names.length);
+            for (int i = 0; i < names.length; i++) {
+                int arrayIndex = getIndex(names[i], groups[i], increments[i]);
+                displacements[i] = getDisplacementForLongIndex(target, arrayIndex);
+                offsetMap.put(displacements[i], i);
+            }
+            Arrays.sort(displacements);
+            // Now apply in order
+            for (int offset : displacements) {
+                int idx = offsetMap.get(offset);
+                proc.apply(idx, increments[idx], displacements[idx]);
+            }
         }
     }
 
@@ -86,6 +118,17 @@
         return BenchmarkCounters.getIndex(name, group, config);
     }
 
+    /**
+     * Patches the increment value in the instruction emitted by this instruction. Use only, if
+     * patching is needed after assembly.
+     *
+     * @param asm
+     * @param increment
+     */
+    public void patchCounterIncrement(Assembler asm, int[] increment) {
+        throw GraalInternalError.unimplemented();
+    }
+
     private static long asLong(JavaConstant value) {
         Kind kind = value.getKind();
         switch (kind) {
@@ -109,4 +152,11 @@
         return (int) l;
     }
 
+    public String[] getNames() {
+        return names;
+    }
+
+    public String[] getGroups() {
+        return groups;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotInstructionProfiling.java	Mon Mar 23 10:27:17 2015 -0700
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.hotspot;
+
+import java.util.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.asm.*;
+import com.oracle.graal.asm.Assembler.*;
+import com.oracle.graal.compiler.common.cfg.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.lir.StandardOp.BlockEndOp;
+import com.oracle.graal.lir.StandardOp.LabelOp;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.graal.lir.gen.*;
+import com.oracle.graal.lir.phases.*;
+
+public class HotSpotInstructionProfiling extends PostAllocationOptimizationPhase {
+    public static final String COUNTER_GROUP = "INSTRUCTION_COUNTER";
+    private final String[] instructionsToProfile;
+
+    public HotSpotInstructionProfiling(String instructionsToProfile) {
+        this.instructionsToProfile = instructionsToProfile.split(",");
+    }
+
+    @Override
+    protected <B extends AbstractBlockBase<B>> void run(TargetDescription target, LIRGenerationResult lirGenRes, List<B> codeEmittingOrder, List<B> linearScanOrder,
+                    BenchmarkCounterFactory counterFactory) {
+        new Analyzer(lirGenRes.getCompilationUnitName(), lirGenRes.getLIR(), counterFactory).run();
+    }
+
+    private class Analyzer {
+        private final LIR lir;
+        private final BenchmarkCounterFactory counterFactory;
+        private final LIRInsertionBuffer buffer;
+        private final String compilationUnitName;
+
+        public Analyzer(String compilationUnitName, LIR lir, BenchmarkCounterFactory counterFactory) {
+            this.lir = lir;
+            this.compilationUnitName = compilationUnitName;
+            this.counterFactory = counterFactory;
+            this.buffer = new LIRInsertionBuffer();
+        }
+
+        public void run() {
+            for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
+                doBlock(block);
+            }
+        }
+
+        public void doBlock(AbstractBlockBase<?> block) {
+            List<LIRInstruction> instructions = lir.getLIRforBlock(block);
+            assert instructions.size() >= 2 : "Malformed block: " + block + ", " + instructions;
+            assert instructions.get(instructions.size() - 1) instanceof BlockEndOp : "Not a BlockEndOp: " + instructions.get(instructions.size() - 1);
+            assert !(instructions.get(instructions.size() - 2) instanceof BlockEndOp) : "Is a BlockEndOp: " + instructions.get(instructions.size() - 2);
+            assert instructions.get(0) instanceof LabelOp : "Not a LabelOp: " + instructions.get(0);
+            assert !(instructions.get(1) instanceof LabelOp) : "Is a LabelOp: " + instructions.get(1);
+            String[] names = new String[instructionsToProfile.length];
+            String[] groups = new String[instructionsToProfile.length];
+            Value[] increments = new Value[instructionsToProfile.length];
+            for (int i = 0; i < instructionsToProfile.length; i++) {
+                names[i] = compilationUnitName;
+                groups[i] = COUNTER_GROUP + " " + instructionsToProfile[i];
+                increments[i] = JavaConstant.INT_0;
+            }
+            HotSpotCounterOp op = (HotSpotCounterOp) counterFactory.createMultiBenchmarkCounter(names, groups, increments);
+            LIRInstruction inst = new InstructionCounterOp(op, instructionsToProfile);
+            assert inst != null;
+            buffer.init(instructions);
+            buffer.append(1, inst);
+            buffer.finish();
+        }
+    }
+
+    /**
+     * After assembly the {@link HotSpotBackend#profileInstructions(LIR, CompilationResultBuilder)}
+     * calls this method for patching the instruction counts into the coutner increment code.
+     */
+    public static void countInstructions(LIR lir, Assembler asm) {
+        InstructionCounterOp lastOp = null;
+        InstructionCounter counter = asm.getInstructionCounter();
+        for (AbstractBlockBase<?> block : lir.codeEmittingOrder()) {
+            for (LIRInstruction inst : lir.getLIRforBlock(block)) {
+                if (inst instanceof InstructionCounterOp) {
+                    InstructionCounterOp currentOp = (InstructionCounterOp) inst;
+
+                    if (lastOp != null) {
+                        int beginPc = lastOp.countOffsetEnd;
+                        int endPc = currentOp.countOffsetBegin;
+                        int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
+                        lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
+                    }
+                    lastOp = ((InstructionCounterOp) inst);
+                }
+            }
+        }
+        if (lastOp != null) {
+            assert lastOp.countOffsetBegin < asm.position();
+            int beginPc = lastOp.countOffsetBegin;
+            int endPc = asm.position();
+            int[] instructionCounts = counter.countInstructions(lastOp.instructionsToProfile, beginPc, endPc);
+            lastOp.delegate.patchCounterIncrement(asm, instructionCounts);
+        }
+    }
+
+    public static class InstructionCounterOp extends LIRInstruction {
+        public static final LIRInstructionClass<InstructionCounterOp> TYPE = LIRInstructionClass.create(InstructionCounterOp.class);
+        private final HotSpotCounterOp delegate;
+        private final String[] instructionsToProfile;
+        private int countOffsetBegin;
+        private int countOffsetEnd;
+
+        public InstructionCounterOp(HotSpotCounterOp delegate, String[] instructionsToProfile) {
+            super(TYPE);
+            this.delegate = delegate;
+            this.instructionsToProfile = instructionsToProfile;
+        }
+
+        @Override
+        public void emitCode(CompilationResultBuilder crb) {
+            countOffsetBegin = crb.asm.position();
+            this.delegate.emitCode(crb);
+            countOffsetEnd = crb.asm.position();
+        }
+
+        public String[] getInstructionsToProfile() {
+            return instructionsToProfile;
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotConstantReflectionProvider.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Mon Mar 23 10:27:17 2015 -0700
@@ -69,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);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInlineInvokePlugin.java	Fri Mar 20 17:26:26 2015 -0700
+++ /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/HotSpotSuitesProvider.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotSuitesProvider.java	Mon Mar 23 10:27:17 2015 -0700
@@ -132,7 +132,11 @@
     }
 
     public LIRSuites createLIRSuites() {
-        return Suites.createDefaultLIRSuites();
+        LIRSuites suites = Suites.createDefaultLIRSuites();
+        String profileInstructions = HotSpotBackend.Options.ASMInstructionProfiling.getValue();
+        if (profileInstructions != null) {
+            suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
+        }
+        return suites;
     }
-
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/ForeignCallStub.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/stubs/SnippetStub.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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.*;
 
@@ -42,6 +43,7 @@
 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.*;
@@ -82,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.
          */
@@ -121,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)") + "}";
+        }
     }
 
     /**
@@ -129,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
@@ -155,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) + "}";
+        }
     }
 
     /**
@@ -1104,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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BytecodeDisassembler.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon Mar 23 10:27:17 2015 -0700
@@ -100,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;
@@ -109,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
@@ -134,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();
@@ -1316,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) {
@@ -2451,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 += " ";
                 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/HIRFrameStateBuilder.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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));
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/lang/Math_sin.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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();
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResult.java	Mon Mar 23 10:27:17 2015 -0700
@@ -56,4 +56,6 @@
     boolean hasForeignCall();
 
     void setForeignCall(boolean b);
+
+    String getCompilationUnitName();
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/gen/LIRGenerationResultBase.java	Mon Mar 23 10:27:17 2015 -0700
@@ -34,10 +34,15 @@
      * Records whether the code being generated makes at least one foreign call.
      */
     private boolean hasForeignCall;
+    /**
+     * Human readable name of this compilation unit.
+     */
+    private final String compilationUnitName;
 
-    public LIRGenerationResultBase(LIR lir, FrameMapBuilder frameMapBuilder) {
+    public LIRGenerationResultBase(String compilationUnitName, LIR lir, FrameMapBuilder frameMapBuilder) {
         this.lir = lir;
         this.frameMapBuilder = frameMapBuilder;
+        this.compilationUnitName = compilationUnitName;
     }
 
     public LIR getLIR() {
@@ -69,4 +74,8 @@
         assert frameMap != null : "getFrameMap() can only be used after calling buildFrameMap()!";
         return frameMap;
     }
+
+    public String getCompilationUnitName() {
+        return compilationUnitName;
+    }
 }
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/profiling/MoveProfiling.java	Mon Mar 23 10:27:17 2015 -0700
@@ -136,12 +136,13 @@
             }
             String[] groups = new String[names.size()];
             Arrays.fill(groups, "Move Operations");
-
-            LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
-            assert inst != null;
-            buffer.init(instructions);
-            buffer.append(1, inst);
-            buffer.finish();
+            if (names.size() > 0) { // Don't pollute LIR when nothing has to be done
+                LIRInstruction inst = counterFactory.createMultiBenchmarkCounter(names.toArray(new String[0]), groups, increments.toArray(new Value[0]));
+                assert inst != null;
+                buffer.init(instructions);
+                buffer.append(1, inst);
+                buffer.finish();
+            }
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardProxyNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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/MemoryPhiNode.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MemoryPhiNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ParameterNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValuePhiNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AddLocationNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ConstantLocationNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IndexedLocationNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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/LoadFieldNode.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Replacements.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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/inlining/InliningUtil.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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());
     }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ObjectAccessTest.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ReplacementsParseTest.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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/WordTest.java	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/WordTest.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/Snippet.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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/mx/mx_graal.py	Fri Mar 20 17:26:26 2015 -0700
+++ b/mx/mx_graal.py	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/build-impl.xml	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/nbproject/genfiles.properties	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/build-impl.xml	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/genfiles.properties	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graal/nbproject/project.xml	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ /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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ /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 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/build-impl.xml	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/SelectionCoordinator/nbproject/genfiles.properties	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties	Mon Mar 23 10:27:17 2015 -0700
@@ -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	Fri Mar 20 17:26:26 2015 -0700
+++ b/src/share/tools/IdealGraphVisualizer/nbproject/project.properties	Mon Mar 23 10:27:17 2015 -0700
@@ -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