changeset 19959:812fc403db8c

Merge.
author Doug Simon <doug.simon@oracle.com>
date Thu, 19 Mar 2015 12:47:06 +0100
parents e018185695f6 (current diff) c39d8bafd342 (diff)
children 999430bcc941
files graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARCScratchRegister.java
diffstat 43 files changed, 529 insertions(+), 947 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.asm.sparc/src/com/oracle/graal/asm/sparc/SPARCMacroAssembler.java	Thu Mar 19 12:47:06 2015 +0100
@@ -39,6 +39,9 @@
      * patched.
      */
     private static final SPARCAddress Placeholder = new SPARCAddress(g0, 0);
+    private final ScratchRegister[] scratchRegister = new ScratchRegister[]{new ScratchRegister(g1), new ScratchRegister(g3)};
+    // Points to the next free scratch register
+    private int nextFreeScratchRegister = 0;
 
     public SPARCMacroAssembler(TargetDescription target, RegisterConfig registerConfig) {
         super(target, registerConfig);
@@ -389,4 +392,26 @@
     public void signx(Register rd) {
         sra(rd, g0, rd);
     }
+
+    public ScratchRegister getScratchRegister() {
+        return scratchRegister[nextFreeScratchRegister++];
+    }
+
+    public class ScratchRegister implements AutoCloseable {
+        private final Register register;
+
+        public ScratchRegister(Register register) {
+            super();
+            this.register = register;
+        }
+
+        public Register getRegister() {
+            return register;
+        }
+
+        public void close() {
+            assert nextFreeScratchRegister > 0 : "Close called too often";
+            nextFreeScratchRegister--;
+        }
+    }
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/GraalOptions.java	Thu Mar 19 12:47:06 2015 +0100
@@ -298,9 +298,6 @@
     public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
-    public static final OptionValue<Boolean> OptTailDuplication = new OptionValue<>(false);
-
-    @Option(help = "", type = OptionType.Debug)
     public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
 
     @Option(help = "", type = OptionType.Debug)
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/FloatStamp.java	Thu Mar 19 12:47:06 2015 +0100
@@ -47,6 +47,7 @@
     public FloatStamp(int bits, double lowerBound, double upperBound, boolean nonNaN) {
         super(bits, OPS);
         assert bits == 64 || (bits == 32 && (Double.isNaN(lowerBound) || (float) lowerBound == lowerBound) && (Double.isNaN(upperBound) || (float) upperBound == upperBound));
+        assert Double.isNaN(lowerBound) == Double.isNaN(upperBound);
         this.lowerBound = lowerBound;
         this.upperBound = upperBound;
         this.nonNaN = nonNaN;
@@ -130,6 +131,10 @@
         return nonNaN;
     }
 
+    public boolean isNaN() {
+        return Double.isNaN(lowerBound);
+    }
+
     public boolean isUnrestricted() {
         return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN;
     }
@@ -629,6 +634,9 @@
         @Override
         public Stamp foldStamp(Stamp s) {
             FloatStamp stamp = (FloatStamp) s;
+            if (stamp.isNaN()) {
+                return stamp;
+            }
             return new FloatStamp(stamp.getBits(), 0, Math.max(-stamp.lowerBound(), stamp.upperBound()), stamp.isNonNaN());
         }
     },
@@ -666,8 +674,19 @@
 
         @Override
         public Stamp foldStamp(Stamp stamp) {
-            assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 32;
-            return StampFactory.forKind(Kind.Int);
+            FloatStamp floatStamp = (FloatStamp) stamp;
+            assert floatStamp.getBits() == 32;
+            boolean mustHaveZero = !floatStamp.isNonNaN();
+            int lowerBound = (int) floatStamp.lowerBound();
+            int upperBound = (int) floatStamp.upperBound();
+            if (mustHaveZero) {
+                if (lowerBound > 0) {
+                    lowerBound = 0;
+                } else if (upperBound < 0) {
+                    upperBound = 0;
+                }
+            }
+            return StampFactory.forInteger(Kind.Int, lowerBound, upperBound);
         }
     },
 
@@ -681,8 +700,19 @@
 
         @Override
         public Stamp foldStamp(Stamp stamp) {
-            assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 32;
-            return StampFactory.forKind(Kind.Long);
+            FloatStamp floatStamp = (FloatStamp) stamp;
+            assert floatStamp.getBits() == 32;
+            boolean mustHaveZero = !floatStamp.isNonNaN();
+            long lowerBound = (long) floatStamp.lowerBound();
+            long upperBound = (long) floatStamp.upperBound();
+            if (mustHaveZero) {
+                if (lowerBound > 0) {
+                    lowerBound = 0;
+                } else if (upperBound < 0) {
+                    upperBound = 0;
+                }
+            }
+            return StampFactory.forInteger(Kind.Long, lowerBound, upperBound);
         }
     },
 
@@ -696,8 +726,19 @@
 
         @Override
         public Stamp foldStamp(Stamp stamp) {
-            assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 64;
-            return StampFactory.forKind(Kind.Int);
+            FloatStamp floatStamp = (FloatStamp) stamp;
+            assert floatStamp.getBits() == 64;
+            boolean mustHaveZero = !floatStamp.isNonNaN();
+            int lowerBound = (int) floatStamp.lowerBound();
+            int upperBound = (int) floatStamp.upperBound();
+            if (mustHaveZero) {
+                if (lowerBound > 0) {
+                    lowerBound = 0;
+                } else if (upperBound < 0) {
+                    upperBound = 0;
+                }
+            }
+            return StampFactory.forInteger(Kind.Int, lowerBound, upperBound);
         }
     },
 
@@ -711,8 +752,19 @@
 
         @Override
         public Stamp foldStamp(Stamp stamp) {
-            assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 64;
-            return StampFactory.forKind(Kind.Long);
+            FloatStamp floatStamp = (FloatStamp) stamp;
+            assert floatStamp.getBits() == 64;
+            boolean mustHaveZero = !floatStamp.isNonNaN();
+            long lowerBound = (long) floatStamp.lowerBound();
+            long upperBound = (long) floatStamp.upperBound();
+            if (mustHaveZero) {
+                if (lowerBound > 0) {
+                    lowerBound = 0;
+                } else if (upperBound < 0) {
+                    upperBound = 0;
+                }
+            }
+            return StampFactory.forInteger(Kind.Long, lowerBound, upperBound);
         }
     },
 
@@ -726,8 +778,9 @@
 
         @Override
         public Stamp foldStamp(Stamp stamp) {
-            assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 32;
-            return StampFactory.forKind(Kind.Double);
+            FloatStamp floatStamp = (FloatStamp) stamp;
+            assert floatStamp.getBits() == 32;
+            return StampFactory.forFloat(Kind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
         }
     },
 
@@ -741,8 +794,9 @@
 
         @Override
         public Stamp foldStamp(Stamp stamp) {
-            assert stamp instanceof FloatStamp && ((FloatStamp) stamp).getBits() == 64;
-            return StampFactory.forKind(Kind.Float);
+            FloatStamp floatStamp = (FloatStamp) stamp;
+            assert floatStamp.getBits() == 64;
+            return StampFactory.forFloat(Kind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());
         }
     });
 }
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/type/IntegerStamp.java	Thu Mar 19 12:47:06 2015 +0100
@@ -973,7 +973,9 @@
         public Stamp foldStamp(Stamp input) {
             IntegerStamp stamp = (IntegerStamp) input;
             assert stamp.getBits() == 32;
-            return StampFactory.forKind(Kind.Float);
+            float lowerBound = stamp.lowerBound();
+            float upperBound = stamp.upperBound();
+            return StampFactory.forFloat(Kind.Float, lowerBound, upperBound, true);
         }
     },
 
@@ -989,7 +991,9 @@
         public Stamp foldStamp(Stamp input) {
             IntegerStamp stamp = (IntegerStamp) input;
             assert stamp.getBits() == 64;
-            return StampFactory.forKind(Kind.Float);
+            float lowerBound = stamp.lowerBound();
+            float upperBound = stamp.upperBound();
+            return StampFactory.forFloat(Kind.Float, lowerBound, upperBound, true);
         }
     },
 
@@ -1005,7 +1009,9 @@
         public Stamp foldStamp(Stamp input) {
             IntegerStamp stamp = (IntegerStamp) input;
             assert stamp.getBits() == 32;
-            return StampFactory.forKind(Kind.Double);
+            double lowerBound = stamp.lowerBound();
+            double upperBound = stamp.upperBound();
+            return StampFactory.forFloat(Kind.Double, lowerBound, upperBound, true);
         }
     },
 
@@ -1021,7 +1027,9 @@
         public Stamp foldStamp(Stamp input) {
             IntegerStamp stamp = (IntegerStamp) input;
             assert stamp.getBits() == 64;
-            return StampFactory.forKind(Kind.Double);
+            double lowerBound = stamp.lowerBound();
+            double upperBound = stamp.upperBound();
+            return StampFactory.forFloat(Kind.Double, lowerBound, upperBound, true);
         }
     });
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java	Thu Mar 19 12:47:06 2015 +0100
@@ -75,10 +75,6 @@
             appendPhase(new LoopFullUnrollPhase(canonicalizer));
         }
 
-        if (OptTailDuplication.getValue()) {
-            appendPhase(new TailDuplicationPhase(canonicalizer));
-        }
-
         if (PartialEscapeAnalysis.getValue()) {
             appendPhase(new PartialEscapePhase(true, canonicalizer));
         }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Thu Mar 19 12:47:06 2015 +0100
@@ -847,12 +847,19 @@
     protected void afterClone(@SuppressWarnings("unused") Node other) {
     }
 
+    public boolean verifyInputs() {
+        for (Node input : inputs()) {
+            assertFalse(input.isDeleted(), "input was deleted");
+            assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph");
+            assertTrue(input.usages().contains(this), "missing usage in input %s", input);
+        }
+        return true;
+    }
+
     public boolean verify() {
         assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
         assertTrue(graph() != null, "null graph");
-        for (Node input : inputs()) {
-            assertTrue(input.usages().contains(this), "missing usage in input %s", input);
-        }
+        verifyInputs();
         for (Node successor : successors()) {
             assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor());
             assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor);
@@ -864,7 +871,7 @@
             while (iterator.hasNext()) {
                 Position pos = iterator.nextPosition();
                 if (pos.get(usage) == this && pos.getInputType() != InputType.Unchecked) {
-                    assert isAllowedUsageType(pos.getInputType()) : "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")";
+                    assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type " + pos.getInputType() + " from " + usage + " to " + this + " (" + pos.getName() + ")");
                 }
             }
         }
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/GraphBuilderContext.java	Thu Mar 19 12:47:06 2015 +0100
@@ -26,7 +26,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 
 /**
@@ -60,15 +59,15 @@
         boolean isIntrinsic();
     }
 
-    <T extends ControlSinkNode> T append(T fixed);
-
-    <T extends ControlSplitNode> T append(T fixed);
+    <T extends ValueNode> T append(T value);
 
-    <T extends FixedWithNextNode> T append(T fixed);
-
-    <T extends FloatingNode> T append(T value);
-
-    <T extends ValueNode> T append(T value);
+    /**
+     * Adds the given floating node to the graph and also adds recursively all referenced inputs.
+     *
+     * @param value the floating node to be added to the graph
+     * @return either the node added or an equivalent node
+     */
+    <T extends ValueNode> T recursiveAppend(T value);
 
     StampProvider getStampProvider();
 
--- a/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.graphbuilderconf/src/com/oracle/graal/graphbuilderconf/InvocationPlugins.java	Thu Mar 19 12:47:06 2015 +0100
@@ -222,10 +222,10 @@
      */
     private InvocationPlugins parent;
 
-    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess, int estimatePluginCount) {
+    private InvocationPlugins(InvocationPlugins parent, MetaAccessProvider metaAccess) {
         this.registrationThread = Thread.currentThread();
         this.metaAccess = metaAccess;
-        this.registrations = new ArrayList<>(estimatePluginCount);
+        this.registrations = new ArrayList<>(INITIAL_PLUGIN_CAPACITY);
         InvocationPlugins p = parent;
         // Only adopt a non-empty parent
         while (p != null && p.size() == 0) {
@@ -234,21 +234,17 @@
         this.parent = p;
     }
 
-    private static final int DEFAULT_ESTIMATE_PLUGIN_COUNT = 16;
+    private static final int INITIAL_PLUGIN_CAPACITY = 64;
 
     /**
      * Creates a set of invocation plugins with a non-null {@linkplain #getParent() parent}.
      */
     public InvocationPlugins(InvocationPlugins parent) {
-        this(parent, parent.metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT);
+        this(parent, parent.metaAccess);
     }
 
     public InvocationPlugins(MetaAccessProvider metaAccess) {
-        this(metaAccess, DEFAULT_ESTIMATE_PLUGIN_COUNT);
-    }
-
-    public InvocationPlugins(MetaAccessProvider metaAccess, int estimatePluginCount) {
-        this(null, metaAccess, estimatePluginCount);
+        this(null, metaAccess);
     }
 
     /**
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackend.java	Thu Mar 19 12:47:06 2015 +0100
@@ -38,6 +38,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.cfg.*;
 import com.oracle.graal.hotspot.*;
@@ -52,7 +53,6 @@
 import com.oracle.graal.lir.sparc.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.sparc.*;
 
 /**
  * HotSpot SPARC specific backend.
@@ -113,7 +113,7 @@
                     if (SPARCAssembler.isSimm13(address.getDisplacement())) {
                         masm.stx(g0, address);
                     } else {
-                        try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                        try (ScratchRegister sc = masm.getScratchRegister()) {
                             Register scratch = sc.getRegister();
                             new Setx(address.getDisplacement(), scratch).emit(masm);
                             masm.stx(g0, new SPARCAddress(sp, scratch));
@@ -148,7 +148,7 @@
             if (SPARCAssembler.isSimm13(stackpoinerChange)) {
                 masm.save(sp, stackpoinerChange, sp);
             } else {
-                try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
                     Register scratch = sc.getRegister();
                     new Setx(stackpoinerChange, scratch).emit(masm);
                     masm.save(sp, scratch, sp);
@@ -227,7 +227,7 @@
                 CallingConvention cc = regConfig.getCallingConvention(JavaCall, null, new JavaType[]{getProviders().getMetaAccess().lookupJavaType(Object.class)}, getTarget(), false);
                 Register inlineCacheKlass = g5; // see MacroAssembler::ic_call
 
-                try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
                     Register scratch = sc.getRegister();
                     Register receiver = asRegister(cc.getArgument(0));
                     SPARCAddress src = new SPARCAddress(receiver, config.hubOffset);
@@ -261,7 +261,7 @@
 
         if (unverifiedStub != null) {
             masm.bind(unverifiedStub);
-            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
                 SPARCCall.indirectJmp(crb, masm, scratch, foreignCalls.lookupForeignCall(IC_MISS_HANDLER));
             }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotCounterOp.java	Thu Mar 19 12:47:06 2015 +0100
@@ -27,6 +27,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.*;
@@ -36,19 +37,12 @@
 public class SPARCHotSpotCounterOp extends HotSpotCounterOp {
     public static final LIRInstructionClass<SPARCHotSpotCounterOp> TYPE = LIRInstructionClass.create(SPARCHotSpotCounterOp.class);
 
-    @Temp({OperandFlag.REG}) private AllocatableValue scratch0;
-    @Temp({OperandFlag.REG}) private AllocatableValue scratch1;
-
-    public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue scratch0, AllocatableValue scratch1) {
+    public SPARCHotSpotCounterOp(String name, String group, Value increment, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
         super(TYPE, name, group, increment, registers, config);
-        this.scratch0 = scratch0;
-        this.scratch1 = scratch1;
     }
 
-    public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config, AllocatableValue scratch0, AllocatableValue scratch1) {
+    public SPARCHotSpotCounterOp(String[] names, String[] groups, Value[] increments, HotSpotRegistersProvider registers, HotSpotVMConfig config) {
         super(TYPE, names, groups, increments, registers, config);
-        this.scratch0 = scratch0;
-        this.scratch1 = scratch1;
     }
 
     @Override
@@ -58,27 +52,32 @@
 
         // address for counters array
         SPARCAddress countersArrayAddr = new SPARCAddress(thread, config.graalCountersThreadOffset);
-        Register countersArrayReg = asRegister(scratch0);
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
+            Register countersArrayReg = scratch.getRegister();
 
-        // load counters array
-        masm.ldx(countersArrayAddr, countersArrayReg);
+            // load counters array
+            masm.ldx(countersArrayAddr, countersArrayReg);
 
-        forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+            forEachCounter((name, group, increment) -> emitIncrement(masm, target, countersArrayReg, name, group, increment));
+        }
     }
 
     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)));
-        Register counterReg = asRegister(scratch1);
-        // load counter value
-        masm.ldx(counterAddr, counterReg);
-        // increment counter
-        if (isConstant(increment)) {
-            masm.add(counterReg, asInt(asConstant(increment)), counterReg);
-        } else {
-            masm.add(counterReg, asRegister(increment), counterReg);
+
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
+            Register counterReg = scratch.getRegister();
+            // load counter value
+            masm.ldx(counterAddr, counterReg);
+            // increment counter
+            if (isConstant(increment)) {
+                masm.add(counterReg, asInt(asConstant(increment)), counterReg);
+            } else {
+                masm.add(counterReg, asRegister(increment), counterReg);
+            }
+            // store counter value
+            masm.stx(counterReg, counterAddr);
         }
-        // store counter value
-        masm.stx(counterReg, counterAddr);
     }
 }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotDeoptimizeCallerOp.java	Thu Mar 19 12:47:06 2015 +0100
@@ -26,10 +26,10 @@
 
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.sparc.*;
-import com.oracle.graal.sparc.*;
 
 /**
  * Removes the current frame and tail calls the uncommon trap routine.
@@ -52,7 +52,7 @@
         // HotSpotFrameContext frameContext = backend.new HotSpotFrameContext(isStub);
         // frameContext.enter(crb);
 
-        try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
             Register scratch = sc.getRegister();
             SPARCCall.indirectJmp(crb, masm, scratch, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER));
         }
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotJumpToExceptionHandlerInCallerOp.java	Thu Mar 19 12:47:06 2015 +0100
@@ -31,9 +31,9 @@
 import com.oracle.graal.asm.sparc.*;
 import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
 import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
-import com.oracle.graal.sparc.*;
 
 /**
  * Sets up the arguments for an exception handler in the callers frame, removes the current frame
@@ -69,7 +69,7 @@
 
         // Restore SP from L7 if the exception PC is a method handle call site.
         SPARCAddress dst = new SPARCAddress(thread, isMethodHandleReturnOffset);
-        try (SPARCScratchRegister scratch = SPARCScratchRegister.get()) {
+        try (ScratchRegister scratch = masm.getScratchRegister()) {
             Register scratchReg = scratch.getRegister();
             masm.lduw(dst, scratchReg);
             masm.cmp(scratchReg, scratchReg);
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotLIRGenerator.java	Thu Mar 19 12:47:06 2015 +0100
@@ -49,7 +49,6 @@
 import com.oracle.graal.lir.sparc.SPARCMove.NullCheckOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreConstantOp;
 import com.oracle.graal.lir.sparc.SPARCMove.StoreOp;
-import com.oracle.graal.sparc.*;
 
 public class SPARCHotSpotLIRGenerator extends SPARCLIRGenerator implements HotSpotLIRGenerator {
 
@@ -368,28 +367,18 @@
     @Override
     public LIRInstruction createBenchmarkCounter(String name, String group, Value increment) {
         if (BenchmarkCounters.enabled) {
-            try (SPARCScratchRegister sc0 = SPARCScratchRegister.get()) {
-                RegisterValue scratch0 = sc0.getRegister().asValue(getLIRKindTool().getWordKind());
-                try (SPARCScratchRegister sc1 = SPARCScratchRegister.get()) {
-                    RegisterValue scratch1 = sc1.getRegister().asValue(getLIRKindTool().getWordKind());
-                    return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config, scratch0, scratch1);
-                }
-            }
+            return new SPARCHotSpotCounterOp(name, group, increment, getProviders().getRegisters(), config);
+        } else {
+            return null;
         }
-        return null;
     }
 
     @Override
     public LIRInstruction createMultiBenchmarkCounter(String[] names, String[] groups, Value[] increments) {
         if (BenchmarkCounters.enabled) {
-            try (SPARCScratchRegister sc0 = SPARCScratchRegister.get()) {
-                RegisterValue scratch0 = sc0.getRegister().asValue(getLIRKindTool().getWordKind());
-                try (SPARCScratchRegister sc1 = SPARCScratchRegister.get()) {
-                    RegisterValue scratch1 = sc1.getRegister().asValue(getLIRKindTool().getWordKind());
-                    return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config, scratch0, scratch1);
-                }
-            }
+            return new SPARCHotSpotCounterOp(names, groups, increments, getProviders().getRegisters(), config);
+        } else {
+            return null;
         }
-        return null;
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/BenchmarkCounters.java	Thu Mar 19 12:47:06 2015 +0100
@@ -85,6 +85,8 @@
                        "  dacapo = 'err, starting =====, PASSED in'%n" +
                        "  specjvm2008 = 'out,Iteration ~ (~s) begins:,Iteration ~ (~s) ends:'", type = OptionType.Debug)
         private static final OptionValue<String> BenchmarkDynamicCounters = new OptionValue<>(null);
+        @Option(help = "Use grouping separators for number printing", type = OptionType.Debug)
+        private static final OptionValue<Boolean> DynamicCountersPrintGroupSeparator = new OptionValue<>(true);
         //@formatter:on
     }
 
@@ -207,28 +209,29 @@
                 cnt--;
             }
 
+            String numFmt = Options.DynamicCountersPrintGroupSeparator.getValue() ? "%,19d" : "%19d";
             if (staticCounter) {
                 out.println("=========== " + group + " (static counters):");
                 for (Map.Entry<Long, String> entry : sorted.entrySet()) {
                     long counter = entry.getKey() / array.length;
-                    out.format(Locale.US, "%,19d %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
+                    out.format(Locale.US, numFmt + " %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
                 }
-                out.format(Locale.US, "%,19d total\n", sum);
+                out.format(Locale.US, numFmt + " total\n", sum);
             } else {
                 if (group.startsWith("~")) {
                     out.println("=========== " + group + " (dynamic counters), time = " + seconds + " s:");
                     for (Map.Entry<Long, String> entry : sorted.entrySet()) {
                         long counter = entry.getKey() / array.length;
-                        out.format(Locale.US, "%,19d/s %3d%%  %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue());
+                        out.format(Locale.US, numFmt + "/s %3d%%  %s\n", (long) (counter / seconds), percentage(counter, sum), entry.getValue());
                     }
-                    out.format(Locale.US, "%,19d/s total\n", (long) (sum / seconds));
+                    out.format(Locale.US, numFmt + "/s total\n", (long) (sum / seconds));
                 } else {
                     out.println("=========== " + group + " (dynamic counters):");
                     for (Map.Entry<Long, String> entry : sorted.entrySet()) {
                         long counter = entry.getKey() / array.length;
-                        out.format(Locale.US, "%,19d %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
+                        out.format(Locale.US, numFmt + " %3d%%  %s\n", counter, percentage(counter, sum), entry.getValue());
                     }
-                    out.format(Locale.US, "%,19d total\n", sum);
+                    out.format(Locale.US, numFmt + " total\n", sum);
                 }
             }
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/DefaultHotSpotLoweringProvider.java	Thu Mar 19 12:47:06 2015 +0100
@@ -109,15 +109,15 @@
         } else if (n instanceof CheckCastDynamicNode) {
             checkcastDynamicSnippets.lower((CheckCastDynamicNode) n, tool);
         } else if (n instanceof InstanceOfNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            if (graph.getGuardsStage().areDeoptsFixed()) {
                 instanceofSnippets.lower((InstanceOfNode) n, tool);
             }
         } else if (n instanceof InstanceOfDynamicNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            if (graph.getGuardsStage().areDeoptsFixed()) {
                 instanceofSnippets.lower((InstanceOfDynamicNode) n, tool);
             }
         } else if (n instanceof ClassIsAssignableFromNode) {
-            if (graph.getGuardsStage() == StructuredGraph.GuardsStage.FIXED_DEOPTS) {
+            if (graph.getGuardsStage().areDeoptsFixed()) {
                 instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool);
             }
         } else if (n instanceof NewInstanceNode) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotGraphBuilderPlugins.java	Thu Mar 19 12:47:06 2015 +0100
@@ -28,6 +28,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.graphbuilderconf.*;
 import com.oracle.graal.graphbuilderconf.GraphBuilderConfiguration.*;
@@ -49,8 +50,6 @@
  */
 public class HotSpotGraphBuilderPlugins {
 
-    private static final int PLUGIN_COUNT_ESTIMATE = 160;
-
     /**
      * Creates a {@link Plugins} object that should be used when running on HotSpot.
      *
@@ -61,8 +60,7 @@
      */
     public static Plugins create(HotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection,
                     SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider, ReplacementsImpl replacements, Architecture arch) {
-
-        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess, PLUGIN_COUNT_ESTIMATE);
+        InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, metaAccess);
 
         Plugins plugins = new Plugins(invocationPlugins);
         NodeIntrinsificationPhase nodeIntrinsification = new NodeIntrinsificationPhase(metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider);
@@ -80,9 +78,6 @@
         registerStableOptionPlugins(invocationPlugins);
         StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, arch, invocationPlugins, !config.useHeapProfiler);
 
-        int size = invocationPlugins.size();
-        assert PLUGIN_COUNT_ESTIMATE >= size : String.format("adjust %s.PLUGIN_COUNT_ESTIMATE to be above or equal to %d", HotSpotGraphBuilderPlugins.class.getSimpleName(), size);
-        assert PLUGIN_COUNT_ESTIMATE - size < 20 : String.format("adjust %s.PLUGIN_COUNT_ESTIMATE to be closer to %d", HotSpotGraphBuilderPlugins.class.getSimpleName(), size);
         return plugins;
     }
 
@@ -92,7 +87,7 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode rcvr) {
                 ObjectStamp objectStamp = (ObjectStamp) rcvr.stamp();
                 ValueNode mirror;
-                if (objectStamp.isExactType() && objectStamp.nonNull()) {
+                if (objectStamp.isExactType() && objectStamp.nonNull() && !GraalOptions.ImmutableCode.getValue()) {
                     mirror = b.append(ConstantNode.forConstant(objectStamp.type().getJavaClass(), b.getMetaAccess()));
                 } else {
                     StampProvider stampProvider = b.getStampProvider();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotInvocationPlugins.java	Thu Mar 19 12:47:06 2015 +0100
@@ -38,8 +38,8 @@
 final class HotSpotInvocationPlugins extends InvocationPlugins {
     final HotSpotVMConfig config;
 
-    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess, int estimatePluginCount) {
-        super(metaAccess, estimatePluginCount);
+    public HotSpotInvocationPlugins(HotSpotVMConfig config, MetaAccessProvider metaAccess) {
+        super(metaAccess);
         this.config = config;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/ClassGetClassLoader0Node.java	Thu Mar 19 12:47:06 2015 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.nodes;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.hotspot.meta.*;
@@ -53,7 +54,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool) {
         ValueNode javaClass = getJavaClass();
-        if (javaClass.isConstant()) {
+        if (javaClass.isConstant() && !GraalOptions.ImmutableCode.getValue()) {
             HotSpotObjectConstant c = (HotSpotObjectConstant) javaClass.asConstant();
             JavaConstant classLoader = c.getClassLoader();
             if (classLoader != null) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/OnStackReplacementPhase.java	Thu Mar 19 12:47:06 2015 +0100
@@ -76,6 +76,7 @@
             }
 
             LoopTransformations.peel(osrLoop);
+            osr.replaceAtUsages(InputType.Guard, AbstractBeginNode.prevBegin((FixedNode) osr.predecessor()));
             for (Node usage : osr.usages().snapshot()) {
                 ProxyNode proxy = (ProxyNode) usage;
                 proxy.replaceAndDelete(proxy.value());
@@ -107,6 +108,8 @@
                 assert value == null || value instanceof OSRLocalNode;
             }
         }
+        osr.replaceAtUsages(InputType.Guard, osrStart);
+        assert osr.usages().isEmpty();
 
         GraphUtil.killCFG(start);
 
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/AbstractBytecodeParser.java	Thu Mar 19 12:47:06 2015 +0100
@@ -1033,7 +1033,7 @@
 
     protected abstract ValueNode appendConstant(JavaConstant constant);
 
-    protected abstract ValueNode append(ValueNode v);
+    protected abstract <T extends ValueNode> T append(T v);
 
     protected boolean isNeverExecutedCode(double probability) {
         return probability == 0 && optimisticOpts.removeNeverExecutedCode();
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu Mar 19 12:47:06 2015 +0100
@@ -1487,61 +1487,41 @@
                 return ConstantNode.forConstant(constant, metaAccess, currentGraph);
             }
 
-            @SuppressWarnings("unchecked")
             @Override
-            public ValueNode append(ValueNode v) {
+            public <T extends ValueNode> T append(T v) {
                 if (v.graph() != null) {
-                    // This node was already appended to the graph.
                     return v;
                 }
-                if (v instanceof ControlSinkNode) {
-                    return append((ControlSinkNode) v);
-                }
-                if (v instanceof ControlSplitNode) {
-                    return append((ControlSplitNode) v);
-                }
-                if (v instanceof FixedWithNextNode) {
-                    return append((FixedWithNextNode) v);
+                T added = currentGraph.addOrUnique(v);
+                if (added == v) {
+                    updateLastInstruction(v);
                 }
-                if (v instanceof FloatingNode) {
-                    return append((FloatingNode) v);
-                }
-                throw GraalInternalError.shouldNotReachHere("Can not append Node of type: " + v.getClass().getName());
-            }
-
-            public <T extends ControlSinkNode> T append(T fixed) {
-                assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
-                assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-                T added = currentGraph.add(fixed);
-                lastInstr.setNext(added);
-                lastInstr = null;
                 return added;
             }
 
-            public <T extends ControlSplitNode> T append(T fixed) {
-                assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
-                assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-                T added = currentGraph.add(fixed);
-                lastInstr.setNext(added);
-                lastInstr = null;
+            public <T extends ValueNode> T recursiveAppend(T v) {
+                if (v.graph() != null) {
+                    return v;
+                }
+                T added = currentGraph.addOrUniqueWithInputs(v);
+                if (added == v) {
+                    updateLastInstruction(v);
+                }
                 return added;
             }
 
-            public <T extends FixedWithNextNode> T append(T fixed) {
-                assert !fixed.isAlive() && !fixed.isDeleted() : "instruction should not have been appended yet";
-                assert lastInstr.next() == null : "cannot append instruction to instruction which isn't end (" + lastInstr + "->" + lastInstr.next() + ")";
-                T added = currentGraph.add(fixed);
-                lastInstr.setNext(added);
-                lastInstr = added;
-                return added;
-            }
-
-            public <T extends FloatingNode> T append(T v) {
-                if (v.graph() != null) {
-                    return v;
+            private <T extends ValueNode> void updateLastInstruction(T v) {
+                if (v instanceof FixedNode) {
+                    FixedNode fixedNode = (FixedNode) v;
+                    lastInstr.setNext(fixedNode);
+                    if (fixedNode instanceof FixedWithNextNode) {
+                        FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
+                        assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
+                        lastInstr = fixedWithNextNode;
+                    } else {
+                        lastInstr = null;
+                    }
                 }
-                T added = currentGraph.unique(v);
-                return added;
             }
 
             private Target checkLoopExit(FixedNode target, BciBlock targetBlock, HIRFrameStateBuilder state) {
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCArithmetic.java	Thu Mar 19 12:47:06 2015 +0100
@@ -37,7 +37,7 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.asm.*;
@@ -371,7 +371,7 @@
                 masm.mulx(asIntReg(src1), asIntReg(src2), asIntReg(dst));
                 break;
             case IMULCC:
-                try (SPARCScratchRegister tmpScratch = SPARCScratchRegister.get()) {
+                try (ScratchRegister tmpScratch = masm.getScratchRegister()) {
                     Register tmp = tmpScratch.getRegister();
                     masm.mulx(asIntReg(src1), asIntReg(src2), asIntReg(dst));
                     Label noOverflow = new Label();
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCControlFlow.java	Thu Mar 19 12:47:06 2015 +0100
@@ -39,6 +39,7 @@
 import com.oracle.graal.asm.sparc.SPARCAssembler.BranchPredict;
 import com.oracle.graal.asm.sparc.SPARCAssembler.CC;
 import com.oracle.graal.asm.sparc.SPARCAssembler.ConditionFlag;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
 import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.compiler.common.calc.*;
@@ -47,7 +48,6 @@
 import com.oracle.graal.lir.SwitchStrategy.BaseSwitchClosure;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.sparc.SPARC.CPUFeature;
-import com.oracle.graal.sparc.*;
 
 public class SPARCControlFlow {
 
@@ -219,21 +219,14 @@
                 actualConditionFlag = actualConditionFlag.mirror();
             }
             boolean isValidConstant = isConstant(actualY) && isSimm5(asConstant(actualY));
-            SPARCScratchRegister scratch = null;
-            try {
+            try (ScratchRegister scratch = masm.getScratchRegister()) {
                 if (isConstant(actualY) && !isValidConstant) { // Make sure, the y value is loaded
-                    scratch = SPARCScratchRegister.get();
                     Value scratchValue = scratch.getRegister().asValue(actualY.getLIRKind());
                     SPARCMove.move(crb, masm, scratchValue, actualY, SPARCDelayedControlTransfer.DUMMY);
                     actualY = scratchValue;
                 }
                 emitCBCond(masm, actualX, actualY, actualTrueTarget, actualConditionFlag);
                 masm.nop();
-            } finally {
-                if (scratch != null) {
-                    // release the scratch if used
-                    scratch.close();
-                }
             }
             if (needJump) {
                 masm.jmp(actualFalseTarget);
@@ -481,14 +474,14 @@
             if (isSimm13(lowKey)) {
                 masm.sub(value, lowKey, scratchReg);
             } else {
-                try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                try (ScratchRegister sc = masm.getScratchRegister()) {
                     Register scratch2 = sc.getRegister();
                     new Setx(lowKey, scratch2).emit(masm);
                     masm.sub(value, scratch2, scratchReg);
                 }
             }
             int upperLimit = highKey - lowKey;
-            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch2 = sc.getRegister();
                 if (isSimm13(upperLimit)) {
                     masm.cmp(scratchReg, upperLimit);
--- a/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.lir.sparc/src/com/oracle/graal/lir/sparc/SPARCMove.java	Thu Mar 19 12:47:06 2015 +0100
@@ -31,7 +31,7 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.asm.sparc.*;
-import com.oracle.graal.asm.sparc.SPARCMacroAssembler.Setx;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.*;
 import com.oracle.graal.compiler.common.*;
 import com.oracle.graal.lir.*;
 import com.oracle.graal.lir.StandardOp.ImplicitNullCheck;
@@ -133,7 +133,7 @@
             Kind inputKind = (Kind) input.getPlatformKind();
             Kind resultKind = (Kind) result.getPlatformKind();
             int resultKindSize = crb.target.getSizeInBytes(resultKind);
-            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
                 SPARCAddress tempAddress = generateSimm13OffsetLoad((SPARCAddress) crb.asAddress(temp), masm, scratch);
                 switch (inputKind) {
@@ -295,7 +295,7 @@
 
         @Override
         public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
                 final SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch);
                 final Register dst = asRegister(result);
@@ -495,7 +495,7 @@
         @Override
         public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
             assert isRegister(input);
-            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
                 SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch);
                 delayedControlTransfer.emitControlTransfer(crb, masm);
@@ -548,7 +548,7 @@
 
         @Override
         public void emitMemAccess(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
-            try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+            try (ScratchRegister sc = masm.getScratchRegister()) {
                 Register scratch = sc.getRegister();
                 SPARCAddress addr = generateSimm13OffsetLoad(address.toAddress(), masm, scratch);
                 delayedControlTransfer.emitControlTransfer(crb, masm);
@@ -604,7 +604,7 @@
                 if (constant.isDefaultForKind() || constant.isNull()) {
                     reg2stack(crb, masm, result, g0.asValue(LIRKind.derive(input)), delaySlotLir);
                 } else {
-                    try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+                    try (ScratchRegister sc = masm.getScratchRegister()) {
                         Register scratch = sc.getRegister();
                         long value = constant.asLong();
                         if (isSimm13(value)) {
@@ -681,7 +681,7 @@
 
     private static void reg2stack(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
         SPARCAddress dst = (SPARCAddress) crb.asAddress(result);
-        try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
             Register scratch = sc.getRegister();
             dst = generateSimm13OffsetLoad(dst, masm, scratch);
             Register src = asRegister(input);
@@ -716,7 +716,7 @@
 
     private static void stack2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, Value input, SPARCDelayedControlTransfer delaySlotLir) {
         SPARCAddress src = (SPARCAddress) crb.asAddress(input);
-        try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
             Register scratch = sc.getRegister();
             src = generateSimm13OffsetLoad(src, masm, scratch);
             Register dst = asRegister(result);
@@ -752,7 +752,7 @@
     }
 
     private static void const2reg(CompilationResultBuilder crb, SPARCMacroAssembler masm, Value result, JavaConstant input, SPARCDelayedControlTransfer delaySlotLir) {
-        try (SPARCScratchRegister sc = SPARCScratchRegister.get()) {
+        try (ScratchRegister sc = masm.getScratchRegister()) {
             Register scratch = sc.getRegister();
             boolean hasVIS3 = ((SPARC) masm.target.arch).getFeatures().contains(CPUFeature.VIS3);
             switch (input.getKind().getStackKind()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu Mar 19 12:47:06 2015 +0100
@@ -79,6 +79,10 @@
         public boolean areFrameStatesAtSideEffects() {
             return !this.areFrameStatesAtDeopts();
         }
+
+        public boolean areDeoptsFixed() {
+            return this.ordinal() >= FIXED_DEOPTS.ordinal();
+        }
     }
 
     /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Thu Mar 19 12:47:06 2015 +0100
@@ -249,6 +249,9 @@
                     return true;
                 } else {
                     customCanonicalizer.simplify(node, tool);
+                    if (node.isDeleted()) {
+                        return true;
+                    }
                 }
             }
             if (nodeClass.isCanonicalizable()) {
@@ -260,7 +263,7 @@
                         canonical = ((BinaryCommutative<?>) node).maybeCommuteInputs();
                     }
                 } catch (Throwable e) {
-                    throw Debug.handle(e);
+                    throw new RuntimeException(e);
                 }
                 if (performReplacement(node, canonical)) {
                     return true;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DominatorConditionalEliminationPhase.java	Thu Mar 19 12:47:06 2015 +0100
@@ -377,7 +377,7 @@
 
         private void processConditionAnchor(ConditionAnchorNode node) {
             tryProofCondition(node.condition(), (guard, result) -> {
-                if (result == node.isNegated()) {
+                if (result != node.isNegated()) {
                     node.replaceAtUsages(guard);
                     GraphUtil.unlinkFixedNode(node);
                     GraphUtil.killWithUnusedFloatingInputs(node);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Thu Mar 19 12:46:38 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,575 +0,0 @@
-/*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.phases.common;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
-import java.util.*;
-import java.util.function.*;
-
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodeinfo.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.VirtualState.NodeClosure;
-import com.oracle.graal.nodes.debug.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.nodes.virtual.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.tiers.*;
-
-/**
- * This class is a phase that looks for opportunities for tail duplication. The static method
- * {@link #tailDuplicate(AbstractMergeNode, TailDuplicationDecision, List, PhaseContext, CanonicalizerPhase)}
- * can also be used to drive tail duplication from other places, e.g., inlining.
- */
-public class TailDuplicationPhase extends BasePhase<PhaseContext> {
-
-    /*
-     * Various metrics on the circumstances in which tail duplication was/wasn't performed.
-     */
-    private static final DebugMetric metricDuplicationConsidered = Debug.metric("DuplicationConsidered");
-    private static final DebugMetric metricDuplicationPerformed = Debug.metric("DuplicationPerformed");
-
-    private final CanonicalizerPhase canonicalizer;
-
-    @NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
-    static final class DummyAnchorNode extends FixedWithNextNode implements GuardingNode, AnchoringNode {
-        public static final NodeClass<DummyAnchorNode> TYPE = NodeClass.create(DummyAnchorNode.class);
-
-        public DummyAnchorNode() {
-            super(TYPE, StampFactory.forVoid());
-        }
-
-    }
-
-    /**
-     * This interface is used by tail duplication to let clients decide if tail duplication should
-     * be performed.
-     */
-    public interface TailDuplicationDecision {
-
-        /**
-         * Queries if tail duplication should be performed at the given merge. If this method
-         * returns true then the tail duplication will be performed, because all other checks have
-         * happened before.
-         *
-         * @param merge The merge at which tail duplication can be performed.
-         * @param fixedNodeCount The size of the set of fixed nodes that forms the base for the
-         *            duplicated set of nodes.
-         * @return true if the tail duplication should be performed, false otherwise.
-         */
-        boolean doTransform(AbstractMergeNode merge, int fixedNodeCount);
-    }
-
-    /**
-     * A tail duplication decision closure that employs the default algorithm: Check if there are
-     * any phis on the merge whose stamps improve and that have usages within the duplicated set of
-     * fixed nodes.
-     */
-    public static final TailDuplicationDecision DEFAULT_DECISION = new TailDuplicationDecision() {
-
-        public boolean doTransform(AbstractMergeNode merge, int fixedNodeCount) {
-            if (fixedNodeCount < TailDuplicationTrivialSize.getValue()) {
-                return true;
-            }
-            ArrayList<PhiNode> improvements = null;
-            for (PhiNode phi : merge.phis()) {
-                Stamp phiStamp = phi.stamp();
-                for (ValueNode input : phi.values()) {
-                    if (!input.stamp().equals(phiStamp)) {
-                        if (improvements == null) {
-                            improvements = new ArrayList<>();
-                        }
-                        if (!improvements.contains(phi)) {
-                            improvements.add(phi);
-                        }
-                        break;
-                    }
-                }
-            }
-            if (improvements == null) {
-                return false;
-            }
-            FixedNode current = merge;
-            int opportunities = 0;
-            while (current instanceof FixedWithNextNode) {
-                current = ((FixedWithNextNode) current).next();
-                if (current instanceof VirtualizableAllocation) {
-                    return false;
-                }
-                for (PhiNode phi : improvements) {
-                    for (Node input : current.inputs()) {
-                        if (input == phi) {
-                            opportunities++;
-                        }
-                        if (input.inputs().contains(phi)) {
-                            opportunities++;
-                        }
-                    }
-                }
-            }
-            return opportunities > 0;
-        }
-    };
-
-    /**
-     * A tail duplication decision closure that always returns true.
-     */
-    public static final TailDuplicationDecision TRUE_DECISION = new TailDuplicationDecision() {
-
-        @Override
-        public boolean doTransform(AbstractMergeNode merge, int fixedNodeCount) {
-            return true;
-        }
-    };
-
-    public TailDuplicationPhase(CanonicalizerPhase canonicalizer) {
-        this.canonicalizer = canonicalizer;
-    }
-
-    @Override
-    protected void run(StructuredGraph graph, PhaseContext phaseContext) {
-        if (graph.hasNode(AbstractMergeNode.TYPE)) {
-            ToDoubleFunction<FixedNode> nodeProbabilities = new FixedNodeProbabilityCache();
-
-            // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
-            // duplication.
-            for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE).snapshot()) {
-                if (!(merge instanceof LoopBeginNode) && nodeProbabilities.applyAsDouble(merge) >= TailDuplicationProbability.getValue()) {
-                    tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
-                }
-            }
-        }
-    }
-
-    /**
-     * This method attempts to duplicate the tail of the given merge. The merge must not be a
-     * {@link LoopBeginNode}. If the merge is eligible for duplication (at least one fixed node in
-     * its tail, no {@link MonitorEnterNode}/ {@link MonitorExitNode}, non-null
-     * {@link AbstractMergeNode#stateAfter()}) then the decision callback is used to determine
-     * whether the tail duplication should actually be performed. If replacements is non-null, then
-     * this list of {@link PiNode}s is used to replace one value per merge end.
-     *
-     * @param merge The merge whose tail should be duplicated.
-     * @param decision A callback that can make the final decision if tail duplication should occur
-     *            or not.
-     * @param replacements A list of {@link PiNode}s, or null. If this list is non-null then its
-     *            size needs to match the merge's end count. Each entry can either be null or a
-     *            {@link PiNode}, and is used to replace {@link PiNode#object()} with the
-     *            {@link PiNode} in the duplicated branch that corresponds to the entry.
-     * @param phaseContext
-     */
-    public static boolean tailDuplicate(AbstractMergeNode merge, TailDuplicationDecision decision, List<GuardedValueNode> replacements, PhaseContext phaseContext, CanonicalizerPhase canonicalizer) {
-        assert !(merge instanceof LoopBeginNode);
-        assert replacements == null || replacements.size() == merge.forwardEndCount();
-        FixedNode fixed = merge;
-        int fixedCount = 0;
-        while (fixed instanceof FixedWithNextNode) {
-            fixed = ((FixedWithNextNode) fixed).next();
-            if (fixed instanceof CommitAllocationNode || fixed instanceof ControlFlowAnchorNode) {
-                return false;
-            }
-            fixedCount++;
-        }
-        if (fixedCount > 1) {
-            metricDuplicationConsidered.increment();
-            if (decision.doTransform(merge, fixedCount)) {
-                metricDuplicationPerformed.increment();
-                new DuplicationOperation(merge, replacements, canonicalizer).duplicate(phaseContext);
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * This class encapsulates one tail duplication operation on a specific
-     * {@link AbstractMergeNode}.
-     */
-    private static class DuplicationOperation {
-
-        private final AbstractMergeNode merge;
-        private final StructuredGraph graph;
-
-        private final Map<ValueNode, PhiNode> bottomPhis = Node.newMap();
-        private final List<GuardedValueNode> replacements;
-
-        private final CanonicalizerPhase canonicalizer;
-
-        /**
-         * Initializes the tail duplication operation without actually performing any work.
-         *
-         * @param merge The merge whose tail should be duplicated.
-         * @param replacements A list of replacement {@link PiNode}s, or null. If this is non-null,
-         *            then the size of the list needs to match the number of end nodes at the merge.
-         */
-        public DuplicationOperation(AbstractMergeNode merge, List<GuardedValueNode> replacements, CanonicalizerPhase canonicalizer) {
-            this.merge = merge;
-            this.replacements = replacements;
-            this.graph = merge.graph();
-            this.canonicalizer = canonicalizer;
-        }
-
-        /**
-         * Performs the actual tail duplication:
-         * <ul>
-         * <li>Creates a new {@link ValueAnchorNode} at the beginning of the duplicated area, an
-         * transfers all dependencies from the merge to this anchor.</li>
-         * <li>Determines the set of fixed nodes to be duplicated.</li>
-         * <li>Creates the new merge at the bottom of the duplicated area.</li>
-         * <li>Determines the complete set of duplicated nodes.</li>
-         * <li>Performs the actual duplication.</li>
-         * </ul>
-         *
-         * @param phaseContext
-         */
-        private void duplicate(PhaseContext phaseContext) {
-            Debug.log("tail duplication at merge %s in %s", merge, graph.method());
-
-            Mark startMark = graph.getMark();
-
-            DummyAnchorNode anchor = addValueAnchor();
-
-            // determine the fixed nodes that should be duplicated (currently: all nodes up until
-            // the first control
-            // split, end node, deopt or return.
-            ArrayList<FixedNode> fixedNodes = new ArrayList<>();
-            FixedNode fixed = merge.next();
-            FrameState stateAfter = merge.stateAfter();
-            while (fixed instanceof FixedWithNextNode) {
-                fixedNodes.add(fixed);
-                if (fixed instanceof StateSplit && ((StateSplit) fixed).stateAfter() != null) {
-                    stateAfter = ((StateSplit) fixed).stateAfter();
-                }
-                fixed = ((FixedWithNextNode) fixed).next();
-            }
-
-            AbstractEndNode endAfter = createNewMerge(fixed, stateAfter);
-            AbstractMergeNode mergeAfter = endAfter.merge();
-            fixedNodes.add(endAfter);
-            final Set<Node> duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter);
-            mergeAfter.clearEnds();
-            expandDuplicated(duplicatedNodes, mergeAfter);
-
-            List<EndNode> endSnapshot = merge.forwardEnds().snapshot();
-            List<PhiNode> phiSnapshot = merge.phis().snapshot();
-
-            int endIndex = 0;
-            for (final EndNode forwardEnd : merge.forwardEnds()) {
-                Map<Node, Node> duplicates;
-                if (replacements == null || replacements.get(endIndex) == null) {
-                    duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), (DuplicationReplacement) null);
-                } else {
-                    Map<Node, Node> replace = Node.newMap();
-                    replace.put(replacements.get(endIndex).object(), replacements.get(endIndex));
-                    duplicates = graph.addDuplicates(duplicatedNodes, graph, duplicatedNodes.size(), replace);
-                }
-                for (Map.Entry<ValueNode, PhiNode> phi : bottomPhis.entrySet()) {
-                    phi.getValue().initializeValueAt(merge.forwardEndIndex(forwardEnd), (ValueNode) duplicates.get(phi.getKey()));
-                }
-                mergeAfter.addForwardEnd((EndNode) duplicates.get(endAfter));
-
-                // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding
-                // EndNode
-                FixedWithNextNode anchorDuplicate = (FixedWithNextNode) duplicates.get(anchor);
-                // move dependencies on the ValueAnchorNode to the previous BeginNode
-                AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(forwardEnd);
-                anchorDuplicate.replaceAtUsages(InputType.Guard, prevBegin);
-                anchorDuplicate.replaceAtUsages(InputType.Anchor, prevBegin);
-                assert anchorDuplicate.hasNoUsages();
-
-                FixedNode next = anchorDuplicate.next();
-                anchorDuplicate.setNext(null);
-                ((FixedWithNextNode) forwardEnd.predecessor()).setNext(next);
-                anchorDuplicate.safeDelete();
-
-                // re-wire the phi duplicates to the correct input
-                for (PhiNode phi : phiSnapshot) {
-                    PhiNode phiDuplicate = (PhiNode) duplicates.get(phi);
-                    phiDuplicate.replaceAtUsages(phi.valueAt(forwardEnd));
-                    phiDuplicate.safeDelete();
-                }
-                endIndex++;
-            }
-            GraphUtil.killCFG(merge);
-            for (AbstractEndNode forwardEnd : endSnapshot) {
-                forwardEnd.safeDelete();
-            }
-            for (PhiNode phi : phiSnapshot) {
-                // these phis should go away, but they still need to be anchored to a merge to be
-                // valid...
-                if (phi.isAlive()) {
-                    phi.setMerge(mergeAfter);
-                }
-            }
-            canonicalizer.applyIncremental(graph, phaseContext, startMark);
-            Debug.dump(graph, "After tail duplication at %s", merge);
-        }
-
-        /**
-         * Inserts a new ValueAnchorNode after the merge and transfers all dependency-usages (not
-         * phis) to this ValueAnchorNode.
-         *
-         * @return The new {@link ValueAnchorNode} that was created.
-         */
-        private DummyAnchorNode addValueAnchor() {
-            DummyAnchorNode anchor = graph.add(new DummyAnchorNode());
-            graph.addAfterFixed(merge, anchor);
-            merge.replaceAtUsages(InputType.Guard, anchor);
-            merge.replaceAtUsages(InputType.Anchor, anchor);
-            return anchor;
-        }
-
-        /**
-         * Given a set of fixed nodes, this method determines the set of fixed and floating nodes
-         * that needs to be duplicated, i.e., all nodes that due to data flow and other dependencies
-         * needs to be duplicated.
-         *
-         * @param fixedNodes The set of fixed nodes that should be duplicated.
-         * @param stateAfter The frame state of the merge that follows the set of fixed nodes. All
-         *            {@link ValueNode}s reachable from this state are considered to be reachable
-         *            from within the duplicated set of nodes.
-         * @return The set of nodes that need to be duplicated.
-         */
-        private Set<Node> buildDuplicatedNodeSet(final ArrayList<FixedNode> fixedNodes, FrameState stateAfter) {
-            final NodeBitMap aboveBound = graph.createNodeBitMap();
-            final NodeBitMap belowBound = graph.createNodeBitMap();
-
-            final Deque<Node> worklist = new ArrayDeque<>();
-
-            // Build the set of nodes that have (transitive) usages within the duplicatedNodes.
-            // This is achieved by iterating all nodes that are reachable via inputs from the the
-            // fixed nodes.
-            aboveBound.markAll(fixedNodes);
-            worklist.addAll(fixedNodes);
-
-            // the phis at the original merge should always be duplicated
-            for (PhiNode phi : merge.phis()) {
-                aboveBound.mark(phi);
-                worklist.add(phi);
-            }
-
-            NodeClosure<Node> aboveClosure = new NodeClosure<Node>() {
-
-                @Override
-                public void apply(Node usage, Node node) {
-                    if (node instanceof PhiNode && !fixedNodes.contains(((PhiNode) node).merge())) {
-                        // stop iterating: phis belonging to outside merges are known to be outside.
-                    } else if (node instanceof FixedNode) {
-                        // stop iterating: fixed nodes within the given set are traversal roots
-                        // anyway, and all other
-                        // fixed nodes are known to be outside.
-                    } else if (!aboveBound.isMarked(node)) {
-                        worklist.add(node);
-                        aboveBound.mark(node);
-                    }
-                }
-            };
-
-            if (stateAfter != null) {
-                stateAfter.applyToNonVirtual(aboveClosure);
-            }
-            while (!worklist.isEmpty()) {
-                Node current = worklist.remove();
-                for (Node input : current.inputs()) {
-                    aboveClosure.apply(current, input);
-                }
-            }
-
-            // Build the set of nodes that have (transitive) inputs within the duplicatedNodes.
-            // This is achieved by iterating all nodes that are reachable via usages from the fixed
-            // nodes.
-            belowBound.markAll(fixedNodes);
-            worklist.addAll(fixedNodes);
-
-            // the phis at the original merge should always be duplicated
-            for (PhiNode phi : merge.phis()) {
-                belowBound.mark(phi);
-                worklist.add(phi);
-            }
-
-            while (!worklist.isEmpty()) {
-                Node current = worklist.remove();
-                for (Node usage : current.usages()) {
-                    if (usage instanceof PhiNode && !fixedNodes.contains(((PhiNode) usage).merge())) {
-                        // stop iterating: phis belonging to outside merges are known to be outside.
-                    } else if (usage instanceof FixedNode) {
-                        // stop iterating: fixed nodes within the given set are traversal roots
-                        // anyway, and all other
-                        // fixed nodes are known to be outside.
-                    } else if (!belowBound.isMarked(usage)) {
-                        worklist.add(usage);
-                        belowBound.mark(usage);
-                    }
-                }
-            }
-
-            // build the intersection
-            belowBound.intersect(aboveBound);
-            Set<Node> result = Node.newSet();
-            for (Node node : belowBound) {
-                result.add(node);
-            }
-            return result;
-        }
-
-        /**
-         * Creates a new merge and end node construct at the end of the duplicated area. While it is
-         * useless in itself (merge with only one end) it simplifies the later duplication step.
-         *
-         * @param successor The successor of the duplicated set of nodes, i.e., the first node that
-         *            should not be duplicated.
-         * @param stateAfterMerge The frame state that should be used for the merge.
-         * @return The newly created end node.
-         */
-        private AbstractEndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
-            MergeNode newBottomMerge = graph.add(new MergeNode());
-            EndNode newBottomEnd = graph.add(new EndNode());
-            newBottomMerge.addForwardEnd(newBottomEnd);
-            newBottomMerge.setStateAfter(stateAfterMerge);
-            ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd);
-            newBottomMerge.setNext(successor);
-            return newBottomEnd;
-        }
-
-        /**
-         * Expands the set of nodes to be duplicated by looking at a number of conditions:
-         * <ul>
-         * <li>Inputs of type {@link InputType#Value} into the duplicated set will be rerouted to a
-         * new phi node.</li>
-         * <li>Inputs of type {@link InputType#Association}, {@link InputType#Condition} and
-         * {@link InputType#State} into the duplicated set will be rerouted to a duplicated version
-         * of the inside node.</li>
-         * <li>Dependencies into the duplicated nodes will be replaced with dependencies on the
-         * merge.</li>
-         * <li>Inputs of type {@link InputType#Association}, {@link InputType#Condition} and
-         * {@link InputType#State} to outside the duplicated set will cause the outside node to be
-         * pulled into the duplicated set.</li>
-         * </ul>
-         *
-         * @param duplicatedNodes The set of duplicated nodes that will be modified (expanded).
-         * @param newBottomMerge The merge that follows the duplicated set of nodes. It will be used
-         *            for newly created phis and to as a target for dependencies that pointed into
-         *            the duplicated set of nodes.
-         */
-        private void expandDuplicated(Set<Node> duplicatedNodes, AbstractMergeNode newBottomMerge) {
-            Deque<Node> worklist = new ArrayDeque<>(duplicatedNodes);
-
-            while (!worklist.isEmpty()) {
-                Node duplicated = worklist.remove();
-                processUsages(duplicated, duplicatedNodes, newBottomMerge, worklist);
-                processInputs(duplicated, duplicatedNodes, worklist);
-            }
-        }
-
-        private void processUsages(Node duplicated, Set<Node> duplicatedNodes, AbstractMergeNode newBottomMerge, Deque<Node> worklist) {
-            Set<Node> unique = Node.newSet();
-            duplicated.usages().snapshotTo(unique);
-            Node newOutsideClone = null;
-            for (Node usage : unique) {
-                if (!duplicatedNodes.contains(usage)) {
-                    NodePosIterator iter = usage.inputs().iterator();
-                    while (iter.hasNext()) {
-                        Position pos = iter.nextPosition();
-                        if (pos.get(usage) == duplicated) {
-                            switch (pos.getInputType()) {
-                                case Extension:
-                                case Condition:
-                                case State:
-                                    // clone the offending node to the outside
-                                    if (newOutsideClone == null) {
-                                        newOutsideClone = duplicated.copyWithInputs();
-                                        // this might cause other nodes to have outside usages
-                                        for (Node input : newOutsideClone.inputs()) {
-                                            if (duplicatedNodes.contains(input)) {
-                                                worklist.add(input);
-                                            }
-                                        }
-                                    }
-                                    pos.set(usage, newOutsideClone);
-                                    break;
-                                case Guard:
-                                case Anchor:
-                                    // re-route dependencies to the merge
-                                    pos.set(usage, newBottomMerge);
-                                    break;
-                                case Value:
-                                    // introduce a new phi
-                                    ValueNode node = (ValueNode) duplicated;
-                                    PhiNode newPhi = bottomPhis.get(node);
-                                    if (newPhi == null) {
-                                        newPhi = graph.addWithoutUnique(new ValuePhiNode(node.stamp().unrestricted(), newBottomMerge));
-                                        bottomPhis.put(node, newPhi);
-                                        newPhi.addInput(node);
-                                    }
-                                    pos.set(usage, newPhi);
-                                    break;
-                                case Association:
-                                default:
-                                    throw GraalInternalError.shouldNotReachHere();
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        private void processInputs(Node duplicated, Set<Node> duplicatedNodes, Deque<Node> worklist) {
-            // check if this node has an input that lies outside and cannot be shared
-            NodePosIterator iter = duplicated.inputs().iterator();
-            while (iter.hasNext()) {
-                Position pos = iter.nextPosition();
-                Node input = pos.get(duplicated);
-                if (input != null && !duplicatedNodes.contains(input)) {
-                    switch (pos.getInputType()) {
-                        case Extension:
-                        case Condition:
-                        case State:
-                            if (input != merge) {
-                                duplicatedNodes.add(input);
-                                worklist.add(input);
-                            }
-                            break;
-                        case Association:
-                        case Guard:
-                        case Anchor:
-                        case Value:
-                            // no change needed
-                            break;
-                        default:
-                            throw GraalInternalError.shouldNotReachHere();
-                    }
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Thu Mar 19 12:47:06 2015 +0100
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.phases.common.inlining.info;
 
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
@@ -39,10 +37,8 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.inlining.*;
 import com.oracle.graal.phases.common.inlining.info.elem.*;
-import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.phases.util.*;
 
 /**
@@ -52,8 +48,6 @@
  */
 public class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
 
-    private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
-
     private final List<ResolvedJavaMethod> concretes;
     private final double[] methodProbabilities;
     private final double maximumMethodProbability;
@@ -170,7 +164,6 @@
         int numberOfMethods = concretes.size();
         FixedNode continuation = invoke.next();
 
-        ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
         // setup merge and phi nodes for results and exceptions
         AbstractMergeNode returnMerge = graph.add(new MergeNode());
         returnMerge.setStateAfter(invoke.stateAfter());
@@ -257,35 +250,6 @@
             replacementNodes.add(null);
         }
 
-        if (OptTailDuplication.getValue()) {
-            /*
-             * We might want to perform tail duplication at the merge after a type switch, if there
-             * are invokes that would benefit from the improvement in type information.
-             */
-            FixedNode current = returnMerge;
-            int opportunities = 0;
-            do {
-                if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
-                                ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
-                    opportunities++;
-                } else if (current.inputs().contains(originalReceiver)) {
-                    opportunities++;
-                }
-                current = ((FixedWithNextNode) current).next();
-            } while (current instanceof FixedWithNextNode);
-
-            if (opportunities > 0) {
-                metricInliningTailDuplication.increment();
-                Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
-                PhaseContext phaseContext = new PhaseContext(providers);
-                CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
-                if (ImmutableCode.getValue()) {
-                    canonicalizer.disableReadCanonicalization();
-                }
-                TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
-            }
-        }
-
         Collection<Node> canonicalizeNodes = new ArrayList<>();
         // do the actual inlining for every invoke
         for (int i = 0; i < numberOfMethods; i++) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Thu Mar 19 12:47:06 2015 +0100
@@ -150,8 +150,9 @@
                 } else {
                     Block currentBlock = b;
                     assert currentBlock != null;
+
                     Block latestBlock = calcLatestBlock(b, isOutOfLoops, currentNode, currentNodeMap);
-                    assert AbstractControlFlowGraph.dominates(currentBlock, latestBlock) || currentNode instanceof VirtualState : currentNode + " " + currentBlock + " " + latestBlock;
+                    assert checkLatestEarliestRelation(currentNode, currentBlock, latestBlock);
                     if (latestBlock != currentBlock) {
                         if (currentNode instanceof FloatingReadNode) {
 
@@ -200,6 +201,12 @@
         return watchListMap;
     }
 
+    private static boolean checkLatestEarliestRelation(Node currentNode, Block earliestBlock, Block latestBlock) {
+        assert AbstractControlFlowGraph.dominates(earliestBlock, latestBlock) || (currentNode instanceof VirtualState && latestBlock == earliestBlock.getDominator()) : String.format("%s %s %s",
+                        currentNode, earliestBlock, latestBlock);
+        return true;
+    }
+
     private static boolean verifySchedule(ControlFlowGraph cfg, BlockMap<List<Node>> blockToNodesMap, NodeMap<Block> nodeMap) {
         for (Block b : cfg.getBlocks()) {
             List<Node> nodes = blockToNodesMap.get(b);
@@ -414,9 +421,11 @@
         assert currentNode.hasUsages();
         for (Node usage : currentNode.usages()) {
             block = calcBlockForUsage(currentNode, usage, block, currentNodeMap);
+            assert checkLatestEarliestRelation(currentNode, earliestBlock, block);
             if (scheduleOutOfLoops) {
-                while (block.getLoopDepth() > earliestBlock.getLoopDepth()) {
+                while (block.getLoopDepth() > earliestBlock.getLoopDepth() && block != earliestBlock.getDominator()) {
                     block = block.getDominator();
+                    assert checkLatestEarliestRelation(currentNode, earliestBlock, block);
                 }
             }
             if (block == earliestBlock) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu Mar 19 12:47:06 2015 +0100
@@ -151,25 +151,25 @@
         Registration r = new Registration(plugins, declaringClass);
         r.register1("reverseBytes", type, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(kind, b.append(new ReverseBytesNode(value).canonical(null, value)));
+                b.push(kind, b.recursiveAppend(new ReverseBytesNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("bitCount", type, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Int, b.append(new BitCountNode(value).canonical(null, value)));
+                b.push(Kind.Int, b.recursiveAppend(new BitCountNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register2("divideUnsigned", type, type, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) {
-                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
+                b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
                 return true;
             }
         });
         r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode dividend, ValueNode divisor) {
-                b.push(kind, b.append(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
+                b.push(kind, b.recursiveAppend(new UnsignedDivNode(dividend, divisor).canonical(null, dividend, divisor)));
                 return true;
             }
         });
@@ -183,7 +183,7 @@
                 ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
                 ZeroExtendNode charCast = b.append(new ZeroExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
-                b.push(Kind.Char.getStackKind(), b.append(charCast.canonical(null, value)));
+                b.push(Kind.Char.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
         });
@@ -197,7 +197,7 @@
                 ReverseBytesNode reverse = b.append(new ReverseBytesNode(value));
                 RightShiftNode rightShift = b.append(new RightShiftNode(reverse, b.append(ConstantNode.forInt(16))));
                 SignExtendNode charCast = b.append(new SignExtendNode(b.append(new NarrowNode(rightShift, 16)), 32));
-                b.push(Kind.Short.getStackKind(), b.append(charCast.canonical(null, value)));
+                b.push(Kind.Short.getStackKind(), b.recursiveAppend(charCast.canonical(null, value)));
                 return true;
             }
         });
@@ -207,13 +207,13 @@
         Registration r = new Registration(plugins, Float.class);
         r.register1("floatToRawIntBits", float.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Int, b.append(new ReinterpretNode(Kind.Int, value).canonical(null, value)));
+                b.push(Kind.Int, b.recursiveAppend(new ReinterpretNode(Kind.Int, value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Float, b.append(new ReinterpretNode(Kind.Float, value).canonical(null, value)));
+                b.push(Kind.Float, b.recursiveAppend(new ReinterpretNode(Kind.Float, value).canonical(null, value)));
                 return true;
             }
         });
@@ -223,13 +223,13 @@
         Registration r = new Registration(plugins, Double.class);
         r.register1("doubleToRawLongBits", double.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Long, b.append(new ReinterpretNode(Kind.Long, value).canonical(null, value)));
+                b.push(Kind.Long, b.recursiveAppend(new ReinterpretNode(Kind.Long, value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Double, b.append(new ReinterpretNode(Kind.Double, value).canonical(null, value)));
+                b.push(Kind.Double, b.recursiveAppend(new ReinterpretNode(Kind.Double, value).canonical(null, value)));
                 return true;
             }
         });
@@ -239,32 +239,32 @@
         Registration r = new Registration(plugins, Math.class);
         r.register1("abs", Float.TYPE, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Float, b.append(new AbsNode(value).canonical(null, value)));
+                b.push(Kind.Float, b.recursiveAppend(new AbsNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("abs", Double.TYPE, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Double, b.append(new AbsNode(value).canonical(null, value)));
+                b.push(Kind.Double, b.recursiveAppend(new AbsNode(value).canonical(null, value)));
                 return true;
             }
         });
         r.register1("sqrt", Double.TYPE, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                b.push(Kind.Double, b.append(new SqrtNode(value).canonical(null, value)));
+                b.push(Kind.Double, b.recursiveAppend(new SqrtNode(value).canonical(null, value)));
                 return true;
             }
         });
         if (getAndSetEnabled(arch)) {
             r.register1("log", Double.TYPE, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                    b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG)));
+                    b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG)));
                     return true;
                 }
             });
             r.register1("log10", Double.TYPE, new InvocationPlugin() {
                 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode value) {
-                    b.push(Kind.Double, b.append(MathIntrinsicNode.create(value, LOG10)));
+                    b.push(Kind.Double, b.recursiveAppend(MathIntrinsicNode.create(value, LOG10)));
                     return true;
                 }
             });
@@ -313,25 +313,25 @@
         r.register2("belowOrEqual", long.class, long.class, new UnsignedMathPlugin(Condition.BE));
         r.register2("divide", int.class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Int, b.append(new UnsignedDivNode(x, y).canonical(null, x, y)));
+                b.push(Kind.Int, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
         r.register2("divide", long.class, long.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Long, b.append(new UnsignedDivNode(x, y).canonical(null, x, y)));
+                b.push(Kind.Long, b.recursiveAppend(new UnsignedDivNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
         r.register2("remainder", int.class, int.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Int, b.append(new UnsignedRemNode(x, y).canonical(null, x, y)));
+                b.push(Kind.Int, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
         r.register2("remainder", long.class, long.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode x, ValueNode y) {
-                b.push(Kind.Long, b.append(new UnsignedRemNode(x, y).canonical(null, x, y)));
+                b.push(Kind.Long, b.recursiveAppend(new UnsignedRemNode(x, y).canonical(null, x, y)));
                 return true;
             }
         });
@@ -366,14 +366,14 @@
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode object) {
                 ValueNode nullCheckedType = nullCheckedValue(b, type);
                 LogicNode condition = b.append(InstanceOfDynamicNode.create(b.getConstantReflection(), nullCheckedType, object));
-                b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
+                b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
         r.register2("isAssignableFrom", Receiver.class, Class.class, new InvocationPlugin() {
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, ValueNode type, ValueNode otherType) {
-                ClassIsAssignableFromNode condition = b.append(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType));
-                b.push(Kind.Boolean.getStackKind(), b.append(new ConditionalNode(condition).canonical(null)));
+                ClassIsAssignableFromNode condition = b.recursiveAppend(new ClassIsAssignableFromNode(nullCheckedValue(b, type), otherType));
+                b.push(Kind.Boolean.getStackKind(), b.recursiveAppend(new ConditionalNode(condition).canonical(null)));
                 return true;
             }
         });
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/ArrayEqualsNode.java	Thu Mar 19 12:47:06 2015 +0100
@@ -53,13 +53,9 @@
 
     @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
 
-    public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length) {
+    public ArrayEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter Kind kind) {
         super(TYPE, StampFactory.forKind(Kind.Boolean));
-        // Ignore nullness in stamp equality test
-        assert array1.stamp().join(StampFactory.objectNonNull()).equals(array2.stamp().join(StampFactory.objectNonNull()));
-        ObjectStamp array1Stamp = (ObjectStamp) array1.stamp();
-        ResolvedJavaType componentType = array1Stamp.type().getComponentType();
-        this.kind = componentType.getKind();
+        this.kind = kind;
         this.array1 = array1;
         this.array2 = array2;
         this.length = length;
@@ -109,28 +105,39 @@
     }
 
     @NodeIntrinsic
-    public static native boolean equals(boolean[] array1, boolean[] array2, int length);
+    public static native boolean equals(Object array1, Object array2, int length, @ConstantNodeParameter Kind kind);
 
-    @NodeIntrinsic
-    public static native boolean equals(byte[] array1, byte[] array2, int length);
+    public static boolean equals(boolean[] array1, boolean[] array2, int length) {
+        return equals(array1, array2, length, Kind.Boolean);
+    }
 
-    @NodeIntrinsic
-    public static native boolean equals(char[] array1, char[] array2, int length);
+    public static boolean equals(byte[] array1, byte[] array2, int length) {
+        return equals(array1, array2, length, Kind.Byte);
+    }
 
-    @NodeIntrinsic
-    public static native boolean equals(short[] array1, short[] array2, int length);
+    public static boolean equals(char[] array1, char[] array2, int length) {
+        return equals(array1, array2, length, Kind.Char);
+    }
 
-    @NodeIntrinsic
-    public static native boolean equals(int[] array1, int[] array2, int length);
+    public static boolean equals(short[] array1, short[] array2, int length) {
+        return equals(array1, array2, length, Kind.Short);
+    }
 
-    @NodeIntrinsic
-    public static native boolean equals(long[] array1, long[] array2, int length);
+    public static boolean equals(int[] array1, int[] array2, int length) {
+        return equals(array1, array2, length, Kind.Int);
+    }
 
-    @NodeIntrinsic
-    public static native boolean equals(float[] array1, float[] array2, int length);
+    public static boolean equals(long[] array1, long[] array2, int length) {
+        return equals(array1, array2, length, Kind.Long);
+    }
 
-    @NodeIntrinsic
-    public static native boolean equals(double[] array1, double[] array2, int length);
+    public static boolean equals(float[] array1, float[] array2, int length) {
+        return equals(array1, array2, length, Kind.Float);
+    }
+
+    public static boolean equals(double[] array1, double[] array2, int length) {
+        return equals(array1, array2, length, Kind.Double);
+    }
 
     @Override
     public void generate(NodeLIRBuilderTool gen) {
--- a/graal/com.oracle.graal.sparc/src/com/oracle/graal/sparc/SPARCScratchRegister.java	Thu Mar 19 12:46:38 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.sparc;
-
-import com.oracle.graal.api.code.*;
-
-public final class SPARCScratchRegister implements AutoCloseable {
-    private final ThreadLocal<Boolean> locked = new ThreadLocal<>();
-    private final ThreadLocal<Exception> where = new ThreadLocal<>();
-    private final Register register;
-    private static final SPARCScratchRegister scratch1 = new SPARCScratchRegister(SPARC.g3);
-    private static final SPARCScratchRegister scratch2 = new SPARCScratchRegister(SPARC.g1);
-    private static final boolean LOG_REQUEST_STACK = false;
-
-    private SPARCScratchRegister(Register register) {
-        super();
-        this.register = register;
-    }
-
-    public Register getRegister() {
-        if (locked.get() == null) {
-            locked.set(false);
-        }
-        boolean isLocked = locked.get();
-        if (isLocked) {
-            if (LOG_REQUEST_STACK) {
-                where.get().printStackTrace();
-            }
-            throw new RuntimeException("Temp Register is already taken!");
-        } else {
-            if (LOG_REQUEST_STACK) {
-                where.set(new Exception());
-            }
-            locked.set(true);
-            return register;
-        }
-    }
-
-    public void close() {
-        boolean isLocked = locked.get();
-        if (isLocked) {
-            locked.set(false);
-        } else {
-            throw new RuntimeException("Temp Register is not taken!");
-        }
-    }
-
-    public static SPARCScratchRegister get() {
-        if (scratch1.isLocked()) {
-            return scratch2;
-        } else {
-            return scratch1;
-        }
-    }
-
-    public boolean isLocked() {
-        Boolean isLocked = locked.get();
-        if (isLocked == null) {
-            return false;
-        } else {
-            return isLocked;
-        }
-    }
-}
--- a/graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/graal/com.oracle.graal.truffle.hotspot.sparc/src/com/oracle/graal/truffle/hotspot/sparc/SPARCOptimizedCallTargetInstumentationFactory.java	Thu Mar 19 12:47:06 2015 +0100
@@ -35,11 +35,11 @@
 import com.oracle.graal.api.runtime.*;
 import com.oracle.graal.asm.*;
 import com.oracle.graal.asm.sparc.*;
+import com.oracle.graal.asm.sparc.SPARCMacroAssembler.ScratchRegister;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.lir.asm.*;
 import com.oracle.graal.lir.framemap.*;
-import com.oracle.graal.sparc.*;
 import com.oracle.graal.truffle.*;
 import com.oracle.graal.truffle.hotspot.*;
 
@@ -53,7 +53,7 @@
             protected void injectTailCallCode(HotSpotVMConfig config, HotSpotRegistersProvider registers) {
                 @SuppressWarnings("hiding")
                 SPARCMacroAssembler asm = (SPARCMacroAssembler) this.asm;
-                try (SPARCScratchRegister scratch = SPARCScratchRegister.get()) {
+                try (ScratchRegister scratch = asm.getScratchRegister()) {
                     Register thisRegister = codeCache.getRegisterConfig().getCallingConventionRegisters(JavaCall, Object)[0];
                     Register spillRegister = scratch.getRegister();
                     Label doProlog = new Label();
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java	Thu Mar 19 12:47:06 2015 +0100
@@ -45,6 +45,7 @@
         System.out.println("  -e:   sort events by elapsed time");
         System.out.println("  -n:   sort events by name and start");
         System.out.println("  -L:   print eliminated locks");
+        System.out.println("  -Q:   print compile queue activity");
         System.exit(exitcode);
     }
 
@@ -54,6 +55,7 @@
         boolean printInlining = false;
         boolean cleanup = false;
         boolean printEliminatedLocks = false;
+        boolean printCompileQueue = false;
         int index = 0;
 
         while (args.length > index) {
@@ -80,6 +82,9 @@
             } else if (args[index].equals("-L")) {
                 printEliminatedLocks = true;
                 index++;
+            } else if (args[index].equals("-Q")) {
+                printCompileQueue = true;
+                index++;
             } else {
                 break;
             }
@@ -92,32 +97,17 @@
         while (index < args.length) {
             ArrayList<LogEvent> events = LogParser.parse(args[index], cleanup);
 
-            if (printEliminatedLocks) {
-                Collections.sort(events, defaultSort);
-                for (LogEvent e : events) {
-                    if (e instanceof Compilation) {
-                        Compilation c = (Compilation) e;
-                        List<JVMState> eliminated = c.getEliminatedLocks();
-                        if (!eliminated.isEmpty()) {
-                            c.print(System.out);
-                            System.out.println("  Eliminated locks");
-                            for (JVMState jvms : eliminated) {
-                                System.err.print("   ");
-                                while (jvms != null) {
-                                    System.out.printf(" %s.%s@%d", jvms.method.getHolder().replace('/', '.'), jvms.method.getName(), jvms.bci);
-                                    jvms = jvms.outer;
-                                }
-                                System.out.println();
-                            }
-                        }
-                    }
-                }
+            if (printCompileQueue) {
+                printCompileQueue(events, System.out);
+            } else if (printEliminatedLocks) {
+                printEliminatedLocks(events, System.out, defaultSort);
             } else if (statistics) {
                 printStatistics(events, System.out);
             } else {
                 Collections.sort(events, defaultSort);
                 for (LogEvent c : events) {
                     if (c instanceof NMethod) continue;
+                    if (c instanceof TaskEvent) continue;
 
                     System.out.printf("%f ", c.getStart());
                     if (printInlining && c instanceof Compilation) {
@@ -131,7 +121,81 @@
             index++;
         }
     }
+    
+    public static void printCompileQueue(ArrayList<LogEvent> events, PrintStream out) {
+        int[] levels = new int[5];
+        HashMap<String, TaskEvent> tasks = new HashMap<String, TaskEvent>();
+        
+        out.printf("%7s ", "Stamp");
+        for (int i = 1; i <= 4; i++) {
+            out.printf(" Level%d", i);
+        }
+        out.printf("   %10s", "Kind");
+        out.println();
+        for (LogEvent e : events) {
+            if (e instanceof TaskEvent) {
+                boolean demoted = false;
+                TaskEvent t = (TaskEvent) e;
+                TaskEvent start = tasks.get(t.getId());
+                switch (t.getKind()) {
+                case Enqueue:
+                    assert start == null;
+                    levels[t.getLevel()] = levels[t.getLevel()] + 1;
+                    tasks.put(t.getId(), t);
+                    break;
+                    
+                case Finish:
+                case Dequeue:
+                    if (start != null && start.getLevel() != t.getLevel()) {
+                        // Sometimes tasks are moved to a lower
+                        // compilation level when the queue fills.
+                        demoted = true;
+                        levels[start.getLevel()] = levels[start.getLevel()] - 1;
+                    } else {
+                        levels[t.getLevel()] = levels[t.getLevel()] - 1;
+                    }
+                    break;
+                default:
+                    throw new InternalError();
+                }
+                out.printf("%7.3f ", t.getStart());
+                for (int i = 1; i <= 4; i++) {
+                    out.printf(" %6d", levels[i]);
+                }
+                out.printf("   %10s", t.getKind());
+                if (t.getComment() != null) {
+                    out.printf(" %s", t.getComment());
+                }
+                if (demoted) {
+                    out.printf("  %d->%d", start.getLevel(), t.getLevel());
+                }
+                out.println();
+            }
+        }
+    }
 
+    public static void printEliminatedLocks(ArrayList<LogEvent> events, PrintStream out, Comparator<LogEvent> defaultSort) {
+        Collections.sort(events, defaultSort);
+        for (LogEvent e : events) {
+            if (e instanceof Compilation) {
+                Compilation c = (Compilation) e;
+                List<JVMState> eliminated = c.getEliminatedLocks();
+                if (!eliminated.isEmpty()) {
+                    c.print(out);
+                    out.println("  Eliminated locks");
+                    for (JVMState jvms : eliminated) {
+                        System.err.print("   ");
+                        while (jvms != null) {
+                            out.printf(" %s.%s@%d", jvms.method.getHolder().replace('/', '.'), jvms.method.getName(), jvms.bci);
+                            jvms = jvms.outer;
+                        }
+                        out.println();
+                    }
+                }
+            }
+        }
+    }
+    
     public static void printStatistics(ArrayList<LogEvent> events, PrintStream out) {
         long cacheSize = 0;
         long maxCacheSize = 0;
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java	Thu Mar 19 12:47:06 2015 +0100
@@ -204,7 +204,7 @@
                     }
                 } else {
                     if (c == null) {
-                        throw new InternalError("can't find compilation " + ble.getId() + " for " + ble);
+                        // throw new InternalError("can't find compilation " + ble.getId() + " for " + ble);
                     }
                 }
             }
@@ -363,6 +363,17 @@
             scopes.peek().last().setReason(search(atts, "reason"));
         } else if (qname.equals("failure")) {
             failureReason = search(atts, "reason");
+        } else if (qname.equals("task_queued")) {
+            String id = makeId(atts);
+            int level = Integer.parseInt(search(atts, "level"));
+            TaskEvent t = new TaskEvent(Double.parseDouble(search(atts, "stamp")), id, level, TaskEvent.Kind.Enqueue);
+            events.add(t);
+        } else if (qname.equals("task_dequeued")) {
+            String id = makeId(atts);
+            int level = Integer.parseInt(search(atts, "level"));
+            TaskEvent t = new TaskEvent(Double.parseDouble(search(atts, "stamp")), id, level, TaskEvent.Kind.Dequeue);
+            t.setComment(search(atts, "comment"));
+            events.add(t);
         } else if (qname.equals("task_done")) {
             compile.setEnd(Double.parseDouble(search(atts, "stamp")));
             if (Integer.parseInt(search(atts, "success")) == 0) {
@@ -425,6 +436,12 @@
                                      parseLong(atts.getValue("size")));
             nmethods.put(id, nm);
             events.add(nm);
+
+            int level = Integer.parseInt(search(atts, "level"));
+            if (level > 0) {
+                TaskEvent t = new TaskEvent(Double.parseDouble(search(atts, "stamp")), id, level, TaskEvent.Kind.Finish);
+                events.add(t);
+            }
         } else if (qname.equals("parse")) {
             Method m = method(search(atts, "method"));
             if (scopes.size() == 0) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/TaskEvent.java	Thu Mar 19 12:47:06 2015 +0100
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * 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.sun.hotspot.tools.compiler;
+
+import java.io.PrintStream;
+
+public class TaskEvent extends BasicLogEvent {
+    private int level;
+    private String comment;
+    private Kind kind;
+
+    enum Kind {
+        Enqueue,
+        Dequeue,
+        Finish
+    }
+    
+    public TaskEvent(double start, String id, int level, Kind kind) {
+        super(start, id);
+        this.level = level;
+        this.kind = kind;
+    }
+
+    void setComment(String comment) {
+        this.comment = comment;
+    }
+
+    String getComment() {
+        return comment;
+    }
+
+    int getLevel() {
+        return level;
+    }
+
+    Kind getKind() {
+        return kind;
+    }
+
+    public void print(PrintStream stream) {
+        stream.printf("%s id='%s' level='%s' %s%n", start, id, level, kind);
+    }
+}
--- a/src/share/vm/compiler/compileBroker.cpp	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/vm/compiler/compileBroker.cpp	Thu Mar 19 12:47:06 2015 +0100
@@ -558,6 +558,24 @@
 
 
 // ------------------------------------------------------------------
+// CompileTask::log_task_dequeued
+void CompileTask::log_task_dequeued(const char* comment) {
+  if (LogCompilation && xtty != NULL) {
+    Thread* thread = Thread::current();
+    ttyLocker ttyl;
+    ResourceMark rm(thread);
+
+    xtty->begin_elem("task_dequeued");
+    log_task(xtty);
+    if (comment != NULL) {
+      xtty->print(" comment='%s'", comment);
+    }
+    xtty->end_elem();
+  }
+}
+
+
+// ------------------------------------------------------------------
 // CompileTask::log_task_start
 void CompileTask::log_task_start(CompileLog* log)   {
   log->begin_head("task");
@@ -1202,10 +1220,12 @@
         blocking = false;
       }
 
-      // Don't allow blocking compiles if inside a class initializer
+      // Don't allow blocking compiles if inside a class initializer or while performing class loading
       vframeStream vfst((JavaThread*) thread);
       for (; !vfst.at_end(); vfst.next()) {
-        if (vfst.method()->is_static_initializer()) {
+        if (vfst.method()->is_static_initializer() ||
+            (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
+             vfst.method()->name() == vmSymbols::loadClass_name())) {
           blocking = false;
           break;
         }
--- a/src/share/vm/compiler/compileBroker.hpp	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/vm/compiler/compileBroker.hpp	Thu Mar 19 12:47:06 2015 +0100
@@ -129,6 +129,7 @@
 
   void         log_task(xmlStream* log);
   void         log_task_queued();
+  void         log_task_dequeued(const char* comment);
   void         log_task_start(CompileLog* log);
   void         log_task_done(CompileLog* log);
 };
--- a/src/share/vm/graal/graalCompiler.cpp	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/vm/graal/graalCompiler.cpp	Thu Mar 19 12:47:06 2015 +0100
@@ -65,6 +65,9 @@
 void GraalCompiler::bootstrap() {
   JavaThread* THREAD = JavaThread::current();
   _bootstrapping = true;
+  // Allow bootstrap to perform Graal compilations of itself
+  bool c1only = GraalCompileWithC1Only;
+  GraalCompileWithC1Only = false;
   ResourceMark rm;
   HandleMark hm;
   if (PrintBootstrap) {
@@ -105,6 +108,7 @@
   if (PrintBootstrap) {
     tty->print_cr(" in " JLONG_FORMAT " ms (compiled %d methods)", os::javaTimeMillis() - start, _methodsCompiled);
   }
+  GraalCompileWithC1Only = c1only;
   _bootstrapping = false;
 }
 
--- a/src/share/vm/graal/graalGlobals.hpp	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/vm/graal/graalGlobals.hpp	Thu Mar 19 12:47:06 2015 +0100
@@ -82,6 +82,12 @@
   product(bool, GraalHProfEnabled, false,                                   \
           "Is Heap  Profiler enabled")                                      \
                                                                             \
+  product(bool, GraalCompileWithC1Only, true,                               \
+          "Only compile Graal classes with C1")                             \
+                                                                            \
+  product(bool, GraalCompileAppFirst, false,                                \
+          "Prioritize application compilations over Graal compilations")    \
+                                                                            \
   develop(bool, GraalUseFastLocking, true,                                  \
           "Use fast inlined locking code")                                  \
                                                                             \
--- a/src/share/vm/runtime/advancedThresholdPolicy.cpp	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp	Thu Mar 19 12:47:06 2015 +0100
@@ -157,6 +157,9 @@
 
 // Called with the queue locked and with at least one element
 CompileTask* AdvancedThresholdPolicy::select_task(CompileQueue* compile_queue) {
+#ifdef COMPILERGRAAL
+  CompileTask *max_non_graal_task = NULL;
+#endif
   CompileTask *max_task = NULL;
   Method* max_method = NULL;
   jlong t = os::javaTimeMillis();
@@ -175,6 +178,7 @@
         if (PrintTieredEvents) {
           print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level());
         }
+        task->log_task_dequeued("stale");
         CompileTaskWrapper ctw(task); // Frees the task
         compile_queue->remove(task);
         method->clear_queued_for_compilation();
@@ -188,9 +192,30 @@
         max_method = method;
       }
     }
+#ifdef COMPILERGRAAL
+    if (GraalCompileAppFirst && (task->comp_level() == CompLevel_full_optimization || !method->has_compiled_code()) &&
+        SystemDictionary::graal_loader() != NULL &&
+        method->method_holder()->class_loader() != SystemDictionary::graal_loader()) {
+      if (max_non_graal_task == NULL) {
+        max_non_graal_task = task;
+      } else {
+        // Select a method with a higher rate
+        if (compare_methods(method, max_non_graal_task->method())) {
+          max_non_graal_task = task;
+        }
+      }
+    }
+#endif
     task = next_task;
   }
 
+#ifdef COMPILERGRAAL
+  if (max_non_graal_task != NULL) {
+    max_task = max_non_graal_task;
+    max_method = max_task->method();
+  }
+#endif
+
   if (max_task->comp_level() == CompLevel_full_profile && TieredStopAtLevel > CompLevel_full_profile
       && is_method_profiled(max_method)) {
     max_task->set_comp_level(CompLevel_limited_profile);
--- a/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp	Thu Mar 19 12:46:38 2015 +0100
+++ b/src/share/vm/runtime/simpleThresholdPolicy.inline.hpp	Thu Mar 19 12:47:06 2015 +0100
@@ -55,6 +55,13 @@
 // Determine if a given method is such a case.
 bool SimpleThresholdPolicy::is_trivial(Method* method) {
   if (method->is_accessor()) return true;
+#ifdef COMPILERGRAAL
+  if (TieredCompilation && GraalCompileWithC1Only &&
+      SystemDictionary::graal_loader() != NULL &&
+      method->method_holder()->class_loader() == SystemDictionary::graal_loader()) {
+    return true;
+  }
+#endif
   if (method->code() != NULL) {
     MethodData* mdo = method->method_data();
     if (mdo != NULL && mdo->num_loops() == 0 &&