changeset 9460:56c12e0c15c1

Merge.
author Doug Simon <doug.simon@oracle.com>
date Tue, 30 Apr 2013 22:22:42 +0200
parents c021bfc839e6 (current diff) ca34e36c53e8 (diff)
children 902a974d55c8 5c258c1feb82
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 92 files changed, 1215 insertions(+), 514 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/DeoptimizationReason.java	Tue Apr 30 22:22:42 2013 +0200
@@ -38,5 +38,6 @@
     Unresolved,
     JavaSubroutineMismatch,
     ArithmeticException,
-    RuntimeConstraint
+    RuntimeConstraint,
+    LoopLimitCheck,
 }
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/SimpleCFGTest.java	Tue Apr 30 22:22:42 2013 +0200
@@ -35,12 +35,12 @@
     public void testImplies() {
         StructuredGraph graph = new StructuredGraph();
 
-        EndNode trueEnd = graph.add(new EndNode());
-        EndNode falseEnd = graph.add(new EndNode());
+        AbstractEndNode trueEnd = graph.add(new EndNode());
+        AbstractEndNode falseEnd = graph.add(new EndNode());
 
-        BeginNode trueBegin = graph.add(new BeginNode());
+        AbstractBeginNode trueBegin = graph.add(new BeginNode());
         trueBegin.setNext(trueEnd);
-        BeginNode falseBegin = graph.add(new BeginNode());
+        AbstractBeginNode falseBegin = graph.add(new BeginNode());
         falseBegin.setNext(falseEnd);
 
         IfNode ifNode = graph.add(new IfNode(null, trueBegin, falseBegin, 0.5));
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/WriteBarrierVerificationTest.java	Tue Apr 30 22:22:42 2013 +0200
@@ -683,7 +683,7 @@
                     }
 
                     @Override
-                    protected State afterSplit(BeginNode node, State oldState) {
+                    protected State afterSplit(AbstractBeginNode node, State oldState) {
                         return new State();
                     }
                 };
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Tue Apr 30 22:22:42 2013 +0200
@@ -146,7 +146,7 @@
 
         plan.runPhases(PhasePosition.LOW_LEVEL, graph);
 
-        LowTierContext lowTierContext = new LowTierContext(runtime, assumptions, replacements, target);
+        LowTierContext lowTierContext = new LowTierContext(runtime, assumptions, replacements, target, optimisticOpts);
         Suites.DEFAULT.getLowTier().apply(graph, lowTierContext);
 
         final SchedulePhase schedule = new SchedulePhase();
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Tue Apr 30 22:22:42 2013 +0200
@@ -471,7 +471,7 @@
     }
 
     @Override
-    public void visitEndNode(EndNode end) {
+    public void visitEndNode(AbstractEndNode end) {
         moveToPhi(end.merge(), end);
     }
 
@@ -482,7 +482,7 @@
     public void visitLoopEnd(LoopEndNode x) {
     }
 
-    private void moveToPhi(MergeNode merge, EndNode pred) {
+    private void moveToPhi(MergeNode merge, AbstractEndNode pred) {
         if (GraalOptions.TraceLIRGeneratorLevel >= 1) {
             TTY.println("MOVE TO PHI from " + pred + " to " + merge);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LowTier.java	Tue Apr 30 22:22:42 2013 +0200
@@ -34,6 +34,8 @@
 
         addPhase(new FrameStateAssignmentPhase());
 
+        addPhase(new ExpandLogicPhase());
+
         addPhase(new DeadCodeEliminationPhase());
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Tue Apr 30 22:22:42 2013 +0200
@@ -477,7 +477,11 @@
     }
 
     public <T> NodeMap<T> createNodeMap() {
-        return new NodeMap<>(this);
+        return createNodeMap(false);
+    }
+
+    public <T> NodeMap<T> createNodeMap(boolean autoGrow) {
+        return new NodeMap<>(this, autoGrow);
     }
 
     public NodeFlood createNodeFlood() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Tue Apr 30 22:22:42 2013 +0200
@@ -759,8 +759,11 @@
     }
 
     public boolean edgesEqual(Node node, Node other) {
+        return inputsEqual(node, other) && successorsEqual(node, other);
+    }
+
+    public boolean inputsEqual(Node node, Node other) {
         assert node.getClass() == clazz && other.getClass() == clazz;
-
         int index = 0;
         while (index < directInputCount) {
             if (getNode(other, inputOffsets[index]) != getNode(node, inputOffsets[index])) {
@@ -775,8 +778,12 @@
             }
             index++;
         }
+        return true;
+    }
 
-        index = 0;
+    public boolean successorsEqual(Node node, Node other) {
+        assert node.getClass() == clazz && other.getClass() == clazz;
+        int index = 0;
         while (index < directSuccessorCount) {
             if (getNode(other, successorOffsets[index]) != getNode(node, successorOffsets[index])) {
                 return false;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeMap.java	Tue Apr 30 22:22:42 2013 +0200
@@ -29,19 +29,23 @@
 public final class NodeMap<T> {
 
     private final Graph graph;
+    private final boolean autogrow;
     private Object[] values;
-    private int size;
 
     public NodeMap(Graph graph) {
+        this(graph, false);
+    }
+
+    public NodeMap(Graph graph, boolean autogrow) {
         this.graph = graph;
-        values = new Object[graph.nodeIdCount()];
-        size = values.length;
+        this.values = new Object[graph.nodeIdCount()];
+        this.autogrow = autogrow;
     }
 
     public NodeMap(NodeMap<T> copyFrom) {
         this.graph = copyFrom.graph;
         this.values = Arrays.copyOf(copyFrom.values, copyFrom.values.length);
-        this.size = copyFrom.size;
+        this.autogrow = copyFrom.autogrow;
     }
 
     @SuppressWarnings("unchecked")
@@ -60,14 +64,21 @@
     }
 
     public int size() {
-        return size;
+        return values.length;
     }
 
     public boolean isNew(Node node) {
-        return node.id() >= size;
+        return node.id() >= size();
+    }
+
+    public void grow() {
+        this.values = Arrays.copyOf(values, graph.nodeIdCount());
     }
 
     private void check(Node node) {
+        if (autogrow && isNew(node)) {
+            grow();
+        }
         assert node.graph() == graph : "this node is not part of the graph";
         assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java	Tue Apr 30 22:22:42 2013 +0200
@@ -394,6 +394,7 @@
     public int deoptReasonJsrMismatch;
     public int deoptReasonDiv0Check;
     public int deoptReasonConstraint;
+    public int deoptReasonLoopLimitCheck;
 
     public int deoptActionNone;
     public int deoptActionMaybeRecompile;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Tue Apr 30 22:22:42 2013 +0200
@@ -733,7 +733,7 @@
             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
             // An unsafe read must not floating outside its block as may float above an explicit
             // null check on its object.
-            memoryRead.dependencies().add(BeginNode.prevBegin(load));
+            memoryRead.dependencies().add(AbstractBeginNode.prevBegin(load));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -997,6 +997,8 @@
                 return config.deoptReasonDiv0Check;
             case RuntimeConstraint:
                 return config.deoptReasonConstraint;
+            case LoopLimitCheck:
+                return config.deoptReasonLoopLimitCheck;
             default:
                 throw GraalInternalError.shouldNotReachHere();
         }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/FrameStateBuilder.java	Tue Apr 30 22:22:42 2013 +0200
@@ -253,7 +253,7 @@
         }
     }
 
-    public void insertProxies(BeginNode begin) {
+    public void insertProxies(AbstractBeginNode begin) {
         for (int i = 0; i < localsSize(); i++) {
             ValueNode value = localAt(i);
             if (value != null) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -679,11 +679,7 @@
     }
 
     private void genGoto() {
-        double probability = profilingInfo.getBranchTakenProbability(bci());
-        if (probability < 0) {
-            probability = 1;
-        }
-        appendGoto(createTarget(probability, currentBlock.successors.get(0), frameState));
+        appendGoto(createTarget(1, currentBlock.successors.get(0), frameState));
         assert currentBlock.numNormalSuccessors() == 1;
     }
 
@@ -725,8 +721,8 @@
         }
         condition = currentGraph.unique(condition);
 
-        BeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
-        BeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
+        AbstractBeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
+        AbstractBeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
 
         IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability);
         append(currentGraph.add(ifNode));
@@ -1493,7 +1489,7 @@
             BlockPlaceholderNode placeholder = (BlockPlaceholderNode) block.firstInstruction;
 
             // The EndNode for the already existing edge.
-            EndNode end = currentGraph.add(new EndNode());
+            AbstractEndNode end = currentGraph.add(new EndNode());
             // The MergeNode that replaces the placeholder.
             MergeNode mergeNode = currentGraph.add(new MergeNode());
             FixedNode next = placeholder.next();
@@ -1508,7 +1504,7 @@
         MergeNode mergeNode = (MergeNode) block.firstInstruction;
 
         // The EndNode for the newly merged edge.
-        EndNode newEnd = currentGraph.add(new EndNode());
+        AbstractEndNode newEnd = currentGraph.add(new EndNode());
         Target target = checkLoopExit(newEnd, block, state);
         FixedNode result = target.fixed;
         block.entryState.merge(mergeNode, target.state);
@@ -1522,9 +1518,9 @@
      * Returns a block begin node with the specified state. If the specified probability is 0, the
      * block deoptimizes immediately.
      */
-    private BeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) {
+    private AbstractBeginNode createBlockTarget(double probability, Block block, FrameStateBuilder stateAfter) {
         FixedNode target = createTarget(probability, block, stateAfter);
-        BeginNode begin = BeginNode.begin(target);
+        AbstractBeginNode begin = AbstractBeginNode.begin(target);
 
         assert !(target instanceof DeoptimizeNode && begin.stateAfter() != null) : "We are not allowed to set the stateAfter of the begin node, because we have to deoptimize "
                         + "to a bci _before_ the actual if, so that the interpreter can update the profiling information.";
@@ -1705,7 +1701,7 @@
         if (block.isLoopHeader) {
             // Create the loop header block, which later will merge the backward branches of the
             // loop.
-            EndNode preLoopEnd = currentGraph.add(new EndNode());
+            AbstractEndNode preLoopEnd = currentGraph.add(new EndNode());
             LoopBeginNode loopBegin = currentGraph.add(new LoopBeginNode());
             lastInstr.setNext(preLoopEnd);
             // Add the single non-loop predecessor of the loop header.
@@ -1773,7 +1769,7 @@
                 frameState.clearNonLiveLocals(currentBlock.localsLiveOut);
             }
             if (lastInstr instanceof StateSplit) {
-                if (lastInstr.getClass() == BeginNode.class) {
+                if (lastInstr.getClass() == AbstractBeginNode.class) {
                     // BeginNodes do not need a frame state
                 } else {
                     StateSplit stateSplit = (StateSplit) lastInstr;
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/JTTTest.java	Tue Apr 30 22:22:42 2013 +0200
@@ -60,9 +60,9 @@
             Object[] args = argsWithReceiver(receiver, argsToBind);
             JavaType[] parameterTypes = signatureToTypes(runtime.lookupJavaMethod(m));
             assert parameterTypes.length == args.length;
-            for (int i = 0; i < argsToBind.length; i++) {
+            for (int i = 0; i < args.length; i++) {
                 LocalNode local = graph.getLocal(i);
-                Constant c = Constant.forBoxed(parameterTypes[i].getKind(), argsToBind[i]);
+                Constant c = Constant.forBoxed(parameterTypes[i].getKind(), args[i]);
                 ConstantNode replacement = ConstantNode.forConstant(c, runtime, graph);
                 local.replaceAtUsages(replacement);
             }
@@ -99,8 +99,10 @@
         Result expect = executeExpected(method, receiver, args);
 
         test(method, expect, receiver, args);
-        this.argsToBind = args;
-        test(method, expect, receiver, args);
-        this.argsToBind = null;
+        if (args.length > 0) {
+            this.argsToBind = args;
+            test(method, expect, receiver, args);
+            this.argsToBind = null;
+        }
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/BasicInductionVariable.java	Tue Apr 30 22:22:42 2013 +0200
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.calc.ConvertNode.Op;
 import com.oracle.graal.nodes.type.*;
 
 public class BasicInductionVariable extends InductionVariable {
@@ -113,8 +115,19 @@
     }
 
     @Override
-    public ValueNode extremumNode() {
-        return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(strideNode(), loop.counted().maxTripCountNode()), init);
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
+        Kind fromKind = phi.kind();
+        Graph graph = phi.graph();
+        ValueNode stride = strideNode();
+        ValueNode maxTripCount = loop.counted().maxTripCountNode(assumePositiveTripCount);
+        ValueNode initNode = this.initNode();
+        if (fromKind != kind) {
+            Op convertOp = Op.getOp(fromKind, kind);
+            stride = graph.unique(new ConvertNode(convertOp, stride));
+            maxTripCount = graph.unique(new ConvertNode(convertOp, maxTripCount));
+            initNode = graph.unique(new ConvertNode(convertOp, initNode));
+        }
+        return IntegerArithmeticNode.add(IntegerArithmeticNode.mul(stride, IntegerArithmeticNode.sub(maxTripCount, ConstantNode.forIntegerKind(kind, 1, graph))), initNode);
     }
 
     @Override
@@ -124,6 +137,6 @@
 
     @Override
     public long constantExtremum() {
-        return constantStride() * loop.counted().constantMaxTripCount() + constantInit();
+        return constantStride() * (loop.counted().constantMaxTripCount() - 1) + constantInit();
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/CountedLoopInfo.java	Tue Apr 30 22:22:42 2013 +0200
@@ -22,9 +22,14 @@
  */
 package com.oracle.graal.loop;
 
+import static com.oracle.graal.nodes.calc.IntegerArithmeticNode.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.loop.InductionVariable.Direction;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 
 public class CountedLoopInfo {
 
@@ -32,19 +37,39 @@
     private InductionVariable iv;
     private ValueNode end;
     private boolean oneOff;
+    private ValueNode overflowGuard;
+    private AbstractBeginNode body;
 
-    CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff) {
+    CountedLoopInfo(LoopEx loop, InductionVariable iv, ValueNode end, boolean oneOff, AbstractBeginNode body) {
         this.loop = loop;
         this.iv = iv;
         this.end = end;
         this.oneOff = oneOff;
+        this.body = body;
     }
 
     public ValueNode maxTripCountNode() {
-        // TODO (gd) stuarte and respect oneOff
-        throw GraalInternalError.unimplemented("division is a fixed node that needs to be inserted into the control flow");
-        // return IntegerArithmeticNode.div(IntegerArithmeticNode.sub(end, iv.initNode()),
-        // iv.strideNode());
+        return maxTripCountNode(false);
+    }
+
+    public ValueNode maxTripCountNode(boolean assumePositive) {
+        StructuredGraph graph = (StructuredGraph) iv.valueNode().graph();
+        Kind kind = iv.valueNode().kind();
+        IntegerArithmeticNode range = IntegerArithmeticNode.sub(end, iv.initNode());
+        if (oneOff) {
+            if (iv.direction() == Direction.Up) {
+                range = IntegerArithmeticNode.add(range, ConstantNode.forIntegerKind(kind, 1, graph));
+            } else {
+                range = IntegerArithmeticNode.sub(range, ConstantNode.forIntegerKind(kind, 1, graph));
+            }
+        }
+        IntegerDivNode div = graph.add(new IntegerDivNode(kind, range, iv.strideNode()));
+        graph.addBeforeFixed(loop.entryPoint(), div);
+        ConstantNode zero = ConstantNode.forIntegerKind(kind, 0, graph);
+        if (assumePositive) {
+            return div;
+        }
+        return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero));
     }
 
     public boolean isConstantMaxTripCount() {
@@ -80,4 +105,53 @@
     public String toString() {
         return "iv=" + iv + " until " + end + (oneOff ? iv.direction() == Direction.Up ? "+1" : "-1" : "");
     }
+
+    public ValueNode getLimit() {
+        return end;
+    }
+
+    public ValueNode getStart() {
+        return iv.initNode();
+    }
+
+    public boolean isLimitIncluded() {
+        return oneOff;
+    }
+
+    public AbstractBeginNode getBody() {
+        return body;
+    }
+
+    public Direction getDirection() {
+        return iv.direction();
+    }
+
+    public ValueNode getOverFlowGuard() {
+        if (overflowGuard == null) {
+            Kind kind = iv.valueNode().kind();
+            Graph graph = iv.valueNode().graph();
+            CompareNode cond; // we use a negated guard with a < condition to achieve a >=
+            ConstantNode one = ConstantNode.forIntegerKind(kind, 1, graph);
+            if (iv.direction() == Direction.Up) {
+                IntegerArithmeticNode v1 = sub(ConstantNode.forIntegerKind(kind, kind.getMaxValue(), graph), sub(iv.strideNode(), one));
+                if (oneOff) {
+                    v1 = sub(v1, one);
+                }
+                cond = graph.unique(new IntegerLessThanNode(v1, end));
+            } else {
+                assert iv.direction() == Direction.Down;
+                IntegerArithmeticNode v1 = add(ConstantNode.forIntegerKind(kind, kind.getMinValue(), graph), add(iv.strideNode(), one));
+                if (oneOff) {
+                    v1 = add(v1, one);
+                }
+                cond = graph.unique(new IntegerLessThanNode(end, v1));
+            }
+            overflowGuard = graph.unique(new GuardNode(cond, BeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true));
+        }
+        return overflowGuard;
+    }
+
+    public Kind getKind() {
+        return iv.valueNode().kind();
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedOffsetInductionVariable.java	Tue Apr 30 22:22:42 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -86,8 +87,8 @@
     }
 
     @Override
-    public ValueNode extremumNode() {
-        return op(offset, base.extremumNode());
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
+        return op(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, offset));
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/DerivedScaledInductionVariable.java	Tue Apr 30 22:22:42 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.type.*;
@@ -96,8 +97,8 @@
     }
 
     @Override
-    public ValueNode extremumNode() {
-        return IntegerArithmeticNode.mul(base.extremumNode(), scale);
+    public ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind) {
+        return IntegerArithmeticNode.mul(base.extremumNode(assumePositiveTripCount, kind), ConvertNode.convert(kind, scale));
     }
 
     @Override
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariable.java	Tue Apr 30 22:22:42 2013 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.loop;
 
+import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
@@ -48,6 +49,10 @@
         this.loop = loop;
     }
 
+    public LoopEx getLoop() {
+        return loop;
+    }
+
     public abstract Direction direction();
 
     public abstract ValueNode valueNode();
@@ -64,7 +69,11 @@
 
     public abstract long constantStride();
 
-    public abstract ValueNode extremumNode();
+    public ValueNode extremumNode() {
+        return extremumNode(false, valueNode().kind());
+    }
+
+    public abstract ValueNode extremumNode(boolean assumePositiveTripCount, Kind kind);
 
     public abstract boolean isConstantExtremum();
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/InductionVariables.java	Tue Apr 30 22:22:42 2013 +0200
@@ -46,7 +46,7 @@
     private Collection<BasicInductionVariable> findBasic() {
         List<BasicInductionVariable> bivs = new LinkedList<>();
         LoopBeginNode loopBegin = loop.loopBegin();
-        EndNode forwardEnd = loopBegin.forwardEnd();
+        AbstractEndNode forwardEnd = loopBegin.forwardEnd();
         for (PhiNode phi : loopBegin.phis()) {
             ValueNode backValue = phi.singleBackValue();
             if (backValue == null) {
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopEx.java	Tue Apr 30 22:22:42 2013 +0200
@@ -39,6 +39,7 @@
     private LoopFragmentWhole whole;
     private CountedLoopInfo counted; // TODO (gd) detect
     private LoopsData data;
+    private InductionVariables ivs;
 
     LoopEx(Loop lirLoop, LoopsData data) {
         this.lirLoop = lirLoop;
@@ -148,9 +149,9 @@
         return data;
     }
 
-    public NodeBitMap nodesInLoopFrom(BeginNode point, BeginNode until) {
-        Collection<BeginNode> blocks = new LinkedList<>();
-        Collection<BeginNode> exits = new LinkedList<>();
+    public NodeBitMap nodesInLoopFrom(AbstractBeginNode point, AbstractBeginNode until) {
+        Collection<AbstractBeginNode> blocks = new LinkedList<>();
+        Collection<AbstractBeginNode> exits = new LinkedList<>();
         Queue<Block> work = new LinkedList<>();
         ControlFlowGraph cfg = loopsData().controlFlowGraph();
         work.add(cfg.blockFor(point));
@@ -169,4 +170,11 @@
         }
         return LoopFragment.computeNodes(point.graph(), blocks, exits);
     }
+
+    public InductionVariables getInductionVariables() {
+        if (ivs == null) {
+            ivs = new InductionVariables(this);
+        }
+        return ivs;
+    }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragment.java	Tue Apr 30 22:22:42 2013 +0200
@@ -145,13 +145,13 @@
         }
     }
 
-    protected static NodeBitMap computeNodes(Graph graph, Collection<BeginNode> blocks) {
-        return computeNodes(graph, blocks, Collections.<BeginNode> emptyList());
+    protected static NodeBitMap computeNodes(Graph graph, Collection<AbstractBeginNode> blocks) {
+        return computeNodes(graph, blocks, Collections.<AbstractBeginNode> emptyList());
     }
 
-    protected static NodeBitMap computeNodes(Graph graph, Collection<BeginNode> blocks, Collection<BeginNode> earlyExits) {
+    protected static NodeBitMap computeNodes(Graph graph, Collection<AbstractBeginNode> blocks, Collection<AbstractBeginNode> earlyExits) {
         final NodeBitMap nodes = graph.createNodeBitMap(true);
-        for (BeginNode b : blocks) {
+        for (AbstractBeginNode b : blocks) {
             for (Node n : b.getBlockNodes()) {
                 if (n instanceof Invoke) {
                     nodes.mark(((Invoke) n).callTarget());
@@ -165,7 +165,7 @@
                 nodes.mark(n);
             }
         }
-        for (BeginNode earlyExit : earlyExits) {
+        for (AbstractBeginNode earlyExit : earlyExits) {
             FrameState stateAfter = earlyExit.stateAfter();
             if (stateAfter != null) {
                 nodes.mark(stateAfter);
@@ -183,7 +183,7 @@
             }
         }
 
-        for (BeginNode b : blocks) {
+        for (AbstractBeginNode b : blocks) {
             for (Node n : b.getBlockNodes()) {
                 for (Node usage : n.usages()) {
                     markFloating(usage, nodes);
@@ -223,8 +223,8 @@
         return false;
     }
 
-    public static Collection<BeginNode> toHirBlocks(Collection<Block> blocks) {
-        List<BeginNode> hir = new ArrayList<>(blocks.size());
+    public static Collection<AbstractBeginNode> toHirBlocks(Collection<Block> blocks) {
+        List<AbstractBeginNode> hir = new ArrayList<>(blocks.size());
         for (Block b : blocks) {
             hir.add(b.getBeginNode());
         }
@@ -238,18 +238,18 @@
     protected void mergeEarlyExits() {
         assert isDuplicate();
         StructuredGraph graph = graph();
-        for (BeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) {
+        for (AbstractBeginNode earlyExit : LoopFragment.toHirBlocks(original().loop().lirLoop().exits)) {
             FixedNode next = earlyExit.next();
             if (earlyExit.isDeleted() || !this.original().contains(earlyExit)) {
                 continue;
             }
-            BeginNode newEarlyExit = getDuplicatedNode(earlyExit);
+            AbstractBeginNode newEarlyExit = getDuplicatedNode(earlyExit);
             if (newEarlyExit == null) {
                 continue;
             }
             MergeNode merge = graph.add(new MergeNode());
-            EndNode originalEnd = graph.add(new EndNode());
-            EndNode newEnd = graph.add(new EndNode());
+            AbstractEndNode originalEnd = graph.add(new EndNode());
+            AbstractEndNode newEnd = graph.add(new EndNode());
             merge.addForwardEnd(originalEnd);
             merge.addForwardEnd(newEnd);
             earlyExit.setNext(originalEnd);
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopFragmentInside.java	Tue Apr 30 22:22:42 2013 +0200
@@ -89,13 +89,13 @@
 
         patchNodes(dataFixBefore);
 
-        BeginNode end = mergeEnds();
+        AbstractBeginNode end = mergeEnds();
 
         original().patchPeeling(this);
 
         mergeEarlyExits();
 
-        BeginNode entry = getDuplicatedNode(loop.loopBegin());
+        AbstractBeginNode entry = getDuplicatedNode(loop.loopBegin());
         FrameState state = entry.stateAfter();
         if (state != null) {
             entry.setStateAfter(null);
@@ -213,24 +213,24 @@
         }
     }
 
-    private BeginNode mergeEnds() {
+    private AbstractBeginNode mergeEnds() {
         assert isDuplicate();
-        List<EndNode> endsToMerge = new LinkedList<>();
-        Map<EndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the
-                                                                 // corresponding loop exits
+        List<AbstractEndNode> endsToMerge = new LinkedList<>();
+        Map<AbstractEndNode, LoopEndNode> reverseEnds = new HashMap<>(); // map peel's exit to the
+        // corresponding loop exits
         LoopBeginNode loopBegin = original().loop().loopBegin();
         for (LoopEndNode le : loopBegin.loopEnds()) {
-            EndNode duplicate = getDuplicatedNode(le);
+            AbstractEndNode duplicate = getDuplicatedNode(le);
             if (duplicate != null) {
                 endsToMerge.add(duplicate);
                 reverseEnds.put(duplicate, le);
             }
         }
         mergedInitializers = new IdentityHashMap<>();
-        BeginNode newExit;
+        AbstractBeginNode newExit;
         StructuredGraph graph = graph();
         if (endsToMerge.size() == 1) {
-            EndNode end = endsToMerge.get(0);
+            AbstractEndNode end = endsToMerge.get(0);
             assert end.usages().count() == 0;
             newExit = graph.add(new BeginNode());
             end.replaceAtPredecessor(newExit);
@@ -245,13 +245,13 @@
                 duplicateState = state.duplicateWithVirtualState();
                 newExitMerge.setStateAfter(duplicateState);
             }
-            for (EndNode end : endsToMerge) {
+            for (AbstractEndNode end : endsToMerge) {
                 newExitMerge.addForwardEnd(end);
             }
 
             for (final PhiNode phi : loopBegin.phis().snapshot()) {
                 final PhiNode firstPhi = graph.add(phi.type() == PhiType.Value ? new PhiNode(phi.kind(), newExitMerge) : new PhiNode(phi.type(), newExitMerge, phi.getIdentity()));
-                for (EndNode end : newExitMerge.forwardEnds()) {
+                for (AbstractEndNode end : newExitMerge.forwardEnds()) {
                     LoopEndNode loopEnd = reverseEnds.get(end);
                     ValueNode prim = prim(phi.valueAt(loopEnd));
                     assert prim != null;
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Tue Apr 30 22:22:42 2013 +0200
@@ -60,12 +60,12 @@
 
     public static boolean shouldUnswitch(LoopEx loop, ControlSplitNode controlSplit) {
         Block postDomBlock = loop.loopsData().controlFlowGraph().blockFor(controlSplit).getPostdominator();
-        BeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
+        AbstractBeginNode postDom = postDomBlock != null ? postDomBlock.getBeginNode() : null;
         int loopTotal = loop.size();
         int inBranchTotal = 0;
         double maxProbability = 0;
         for (Node successor : controlSplit.successors()) {
-            BeginNode branch = (BeginNode) successor;
+            AbstractBeginNode branch = (AbstractBeginNode) successor;
             inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality(); // this may count
                                                                                   // twice because
                                                                                   // of fall-through
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Tue Apr 30 22:22:42 2013 +0200
@@ -78,19 +78,19 @@
         // original loop is used as first successor
         Position firstPosition = successors.nextPosition();
         NodeClass controlSplitClass = controlSplitNode.getNodeClass();
-        controlSplitClass.set(newControlSplit, firstPosition, BeginNode.begin(originalLoop.entryPoint()));
+        controlSplitClass.set(newControlSplit, firstPosition, AbstractBeginNode.begin(originalLoop.entryPoint()));
 
         StructuredGraph graph = (StructuredGraph) controlSplitNode.graph();
         while (successors.hasNext()) {
             Position position = successors.nextPosition();
             // create a new loop duplicate, connect it and simplify it
             LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
-            controlSplitClass.set(newControlSplit, position, BeginNode.begin(duplicateLoop.entryPoint()));
+            controlSplitClass.set(newControlSplit, position, AbstractBeginNode.begin(duplicateLoop.entryPoint()));
             ControlSplitNode duplicatedControlSplit = duplicateLoop.getDuplicatedNode(controlSplitNode);
-            graph.removeSplitPropagate(duplicatedControlSplit, (BeginNode) controlSplitClass.get(duplicatedControlSplit, position));
+            graph.removeSplitPropagate(duplicatedControlSplit, (AbstractBeginNode) controlSplitClass.get(duplicatedControlSplit, position));
         }
         // original loop is simplified last to avoid deleting controlSplitNode too early
-        graph.removeSplitPropagate(controlSplitNode, (BeginNode) controlSplitClass.get(controlSplitNode, firstPosition));
+        graph.removeSplitPropagate(controlSplitNode, (AbstractBeginNode) controlSplitClass.get(controlSplitNode, firstPosition));
         // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms)
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopsData.java	Tue Apr 30 22:22:42 2013 +0200
@@ -31,6 +31,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
 
 public class LoopsData {
 
@@ -92,6 +93,9 @@
             InductionVariables ivs = new InductionVariables(loop);
             LoopBeginNode loopBegin = loop.loopBegin();
             FixedNode next = loopBegin.next();
+            while (next instanceof FixedGuardNode || next instanceof ValueAnchorNode) {
+                next = ((FixedWithNextNode) next).next();
+            }
             if (next instanceof IfNode) {
                 IfNode ifNode = (IfNode) next;
                 boolean negated = false;
@@ -150,7 +154,7 @@
                     default:
                         throw GraalInternalError.shouldNotReachHere();
                 }
-                loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff));
+                loop.setCounted(new CountedLoopInfo(loop, iv, limit, oneOff, negated ? ifNode.falseSuccessor() : ifNode.trueSuccessor()));
             }
         }
     }
@@ -158,4 +162,18 @@
     public ControlFlowGraph controlFlowGraph() {
         return cfg;
     }
+
+    public InductionVariable getInductionVariable(ValueNode value) {
+        InductionVariable match = null;
+        for (LoopEx loop : loops()) {
+            InductionVariable iv = loop.getInductionVariables().get(value);
+            if (iv != null) {
+                if (match != null) {
+                    return null;
+                }
+                match = iv;
+            }
+        }
+        return match;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopSafepointEliminationPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.loop.phases;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.loop.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.tiers.*;
+
+public class LoopSafepointEliminationPhase extends BasePhase<LowTierContext> {
+
+    @Override
+    protected void run(StructuredGraph graph, LowTierContext context) {
+        LoopsData loops = new LoopsData(graph);
+        if (context.getOptimisticOptimizations().useLoopLimitChecks()) {
+            loops.detectedCountedLoops();
+            for (LoopEx loop : loops.countedLoops()) {
+                if (loop.lirLoop().children.isEmpty() && loop.counted().getKind() == Kind.Int) {
+                    loop.loopBegin().dependencies().add(loop.counted().getOverFlowGuard());
+                    for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                        loopEnd.disableSafepoint();
+                    }
+                }
+            }
+        }
+        for (LoopEx loop : loops.countedLoops()) {
+            for (LoopEndNode loopEnd : loop.loopBegin().loopEnds()) {
+                Block b = loops.controlFlowGraph().blockFor(loopEnd);
+                blocks: while (b != loop.lirLoop().header) {
+                    assert b != null;
+                    for (FixedNode node : b.getNodes()) {
+                        if (node instanceof Invoke || node instanceof RuntimeCallNode) {
+                            loopEnd.disableSafepoint();
+                            break blocks;
+                        }
+                    }
+                    b = b.getDominator();
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformLowPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -77,7 +77,7 @@
         sb.append(loop).append(" at ").append(controlSplit).append(" [");
         NodeClassIterator it = controlSplit.successors().iterator();
         while (it.hasNext()) {
-            sb.append(controlSplit.probability((BeginNode) it.next()));
+            sb.append(controlSplit.probability((AbstractBeginNode) it.next()));
             if (it.hasNext()) {
                 sb.append(", ");
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractBeginNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import static com.oracle.graal.graph.iterators.NodePredicates.*;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.iterators.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class AbstractBeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType {
+
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return false;
+    }
+
+    protected AbstractBeginNode() {
+        super(StampFactory.dependency());
+    }
+
+    protected AbstractBeginNode(Stamp stamp) {
+        super(stamp);
+    }
+
+    public static AbstractBeginNode begin(FixedNode with) {
+        if (with instanceof AbstractBeginNode) {
+            return (AbstractBeginNode) with;
+        }
+        AbstractBeginNode begin = with.graph().add(new BeginNode());
+        begin.setNext(with);
+        return begin;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        FixedNode prev = (FixedNode) this.predecessor();
+        if (prev == null) {
+            // This is the start node.
+        } else if (prev instanceof ControlSplitNode) {
+            // This begin node is necessary.
+        } else {
+            // This begin node can be removed and all guards moved up to the preceding begin node.
+            prepareDelete();
+            tool.addToWorkList(next());
+            ((StructuredGraph) graph()).removeFixed(this);
+        }
+    }
+
+    public static AbstractBeginNode prevBegin(FixedNode from) {
+        Node prevBegin = from;
+        while (prevBegin != null) {
+            if (prevBegin instanceof AbstractBeginNode) {
+                return (AbstractBeginNode) prevBegin;
+            }
+            prevBegin = prevBegin.predecessor();
+        }
+        return null;
+    }
+
+    private void evacuateGuards(FixedNode evacuateFrom) {
+        if (!usages().isEmpty()) {
+            AbstractBeginNode prevBegin = prevBegin(evacuateFrom);
+            assert prevBegin != null;
+            for (Node anchored : anchored().snapshot()) {
+                anchored.replaceFirstInput(this, prevBegin);
+            }
+        }
+    }
+
+    public void prepareDelete() {
+        prepareDelete((FixedNode) predecessor());
+    }
+
+    public void prepareDelete(FixedNode evacuateFrom) {
+        removeProxies();
+        evacuateGuards(evacuateFrom);
+    }
+
+    public void removeProxies() {
+        for (ProxyNode vpn : proxies().snapshot()) {
+            // can not use graph.replaceFloating because vpn.value may be null during killCFG
+            vpn.replaceAtUsages(vpn.value());
+            vpn.safeDelete();
+        }
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(predecessor() != null || this == ((StructuredGraph) graph()).start() || this instanceof MergeNode, "begin nodes must be connected");
+        return super.verify();
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        // nop
+    }
+
+    public NodeIterable<GuardNode> guards() {
+        return usages().filter(GuardNode.class);
+    }
+
+    public NodeIterable<Node> anchored() {
+        return usages().filter(isNotA(ProxyNode.class));
+    }
+
+    public NodeIterable<ProxyNode> proxies() {
+        return usages().filter(ProxyNode.class);
+    }
+
+    public NodeIterable<FixedNode> getBlockNodes() {
+        return new AbstractNodeIterable<FixedNode>() {
+
+            @Override
+            public Iterator<FixedNode> iterator() {
+                return new BlockNodeIterator(AbstractBeginNode.this);
+            }
+        };
+    }
+
+    private class BlockNodeIterator implements Iterator<FixedNode> {
+
+        private FixedNode current;
+
+        public BlockNodeIterator(FixedNode next) {
+            this.current = next;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return current != null;
+        }
+
+        @Override
+        public FixedNode next() {
+            FixedNode ret = current;
+            if (ret == null) {
+                throw new NoSuchElementException();
+            }
+            if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) {
+                current = null;
+            } else {
+                current = ((FixedWithNextNode) current).next();
+            }
+            return ret;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractEndNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+public abstract class AbstractEndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable {
+
+    protected AbstractEndNode() {
+        super(StampFactory.forVoid());
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        gen.visitEndNode(this);
+    }
+
+    public MergeNode merge() {
+        return (MergeNode) usages().first();
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(usages().count() <= 1, "at most one usage");
+        return super.verify();
+    }
+
+    @Override
+    public Iterable<? extends Node> cfgSuccessors() {
+        return Arrays.asList(merge());
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -22,32 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public class BeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType {
-
-    @Input(notDataflow = true) private FrameState stateAfter;
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    public boolean hasSideEffect() {
-        return false;
-    }
+public final class BeginNode extends AbstractBeginNode {
 
     public BeginNode() {
         super(StampFactory.dependency());
@@ -57,134 +34,6 @@
         super(stamp);
     }
 
-    public static BeginNode begin(FixedNode with) {
-        if (with instanceof BeginNode) {
-            return (BeginNode) with;
-        }
-        BeginNode begin = with.graph().add(new BeginNode());
-        begin.setNext(with);
-        return begin;
-    }
-
-    @Override
-    public void simplify(SimplifierTool tool) {
-        FixedNode prev = (FixedNode) this.predecessor();
-        if (prev == null) {
-            // This is the start node.
-        } else if (prev instanceof ControlSplitNode) {
-            // This begin node is necessary.
-        } else {
-            // This begin node can be removed and all guards moved up to the preceding begin node.
-            prepareDelete();
-            tool.addToWorkList(next());
-            ((StructuredGraph) graph()).removeFixed(this);
-        }
-    }
-
-    public static BeginNode prevBegin(FixedNode from) {
-        Node prevBegin = from;
-        while (prevBegin != null) {
-            if (prevBegin instanceof BeginNode) {
-                return (BeginNode) prevBegin;
-            }
-            prevBegin = prevBegin.predecessor();
-        }
-        return null;
-    }
-
-    private void evacuateGuards(FixedNode evacuateFrom) {
-        if (!usages().isEmpty()) {
-            BeginNode prevBegin = prevBegin(evacuateFrom);
-            assert prevBegin != null;
-            for (Node anchored : anchored().snapshot()) {
-                anchored.replaceFirstInput(this, prevBegin);
-            }
-        }
-    }
-
-    public void prepareDelete() {
-        prepareDelete((FixedNode) predecessor());
-    }
-
-    public void prepareDelete(FixedNode evacuateFrom) {
-        removeProxies();
-        evacuateGuards(evacuateFrom);
-    }
-
-    public void removeProxies() {
-        for (ProxyNode vpn : proxies().snapshot()) {
-            // can not use graph.replaceFloating because vpn.value may be null during killCFG
-            vpn.replaceAtUsages(vpn.value());
-            vpn.safeDelete();
-        }
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(predecessor() != null || this == ((StructuredGraph) graph()).start() || this instanceof MergeNode, "begin nodes must be connected");
-        return super.verify();
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        // nop
-    }
-
-    public NodeIterable<GuardNode> guards() {
-        return usages().filter(GuardNode.class);
-    }
-
-    public NodeIterable<Node> anchored() {
-        return usages().filter(isNotA(ProxyNode.class));
-    }
-
-    public NodeIterable<ProxyNode> proxies() {
-        return usages().filter(ProxyNode.class);
-    }
-
-    public NodeIterable<FixedNode> getBlockNodes() {
-        return new AbstractNodeIterable<FixedNode>() {
-
-            @Override
-            public Iterator<FixedNode> iterator() {
-                return new BlockNodeIterator(BeginNode.this);
-            }
-        };
-    }
-
-    private class BlockNodeIterator implements Iterator<FixedNode> {
-
-        private FixedNode current;
-
-        public BlockNodeIterator(FixedNode next) {
-            this.current = next;
-        }
-
-        @Override
-        public boolean hasNext() {
-            return current != null;
-        }
-
-        @Override
-        public FixedNode next() {
-            FixedNode ret = current;
-            if (ret == null) {
-                throw new NoSuchElementException();
-            }
-            if (!(current instanceof FixedWithNextNode) || (current instanceof BeginNode && current != BeginNode.this)) {
-                current = null;
-            } else {
-                current = ((FixedWithNextNode) current).next();
-            }
-            return ret;
-        }
-
-        @Override
-        public void remove() {
-            throw new UnsupportedOperationException();
-        }
-    }
-
     @NodeIntrinsic
     public static native BeginNode anchor(@ConstantNodeParameter Stamp stamp);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -25,11 +25,11 @@
 import com.oracle.graal.nodes.type.*;
 
 /**
- * Base class for {@link BeginNode}s that are associated with a frame state. TODO (dnsimon) this not
- * needed until {@link BeginNode} no longer implements {@link StateSplit} which is not possible
+ * Base class for {@link AbstractBeginNode}s that are associated with a frame state. TODO (dnsimon) this not
+ * needed until {@link AbstractBeginNode} no longer implements {@link StateSplit} which is not possible
  * until loop peeling works without requiring begin nodes to have frames states
  */
-public abstract class BeginStateSplitNode extends BeginNode implements StateSplit {
+public abstract class BeginStateSplitNode extends AbstractBeginNode implements StateSplit {
 
     public BeginStateSplitNode() {
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ControlSplitNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -34,5 +34,5 @@
         super(stamp);
     }
 
-    public abstract double probability(BeginNode successor);
+    public abstract double probability(AbstractBeginNode successor);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EndNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -22,35 +22,5 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-public class EndNode extends FixedNode implements Node.IterableNodeType, LIRLowerable {
-
-    public EndNode() {
-        super(StampFactory.forVoid());
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.visitEndNode(this);
-    }
-
-    public MergeNode merge() {
-        return (MergeNode) usages().first();
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(usages().count() <= 1, "at most one usage");
-        return super.verify();
-    }
-
-    @Override
-    public Iterable<? extends Node> cfgSuccessors() {
-        return Arrays.asList(merge());
-    }
+public final class EndNode extends AbstractEndNode {
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/EntryMarkerNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -29,7 +29,7 @@
  * This node will be inserted at point specified by {@link StructuredGraph#getEntryBCI()}, usually
  * by the graph builder.
  */
-public class EntryMarkerNode extends BeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable {
+public class EntryMarkerNode extends AbstractBeginNode implements Node.IterableNodeType, Simplifiable, LIRLowerable {
 
     @Override
     public void simplify(SimplifierTool tool) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -101,7 +101,8 @@
     }
 
     @Override
-    public Negatable negate() {
+    public Negatable negate(LogicNode cond) {
+        assert cond == condition();
         negated = !negated;
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -104,7 +104,8 @@
     }
 
     @Override
-    public Negatable negate() {
+    public Negatable negate(LogicNode cond) {
+        assert cond == condition();
         negated = !negated;
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -43,8 +43,8 @@
  */
 public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, Negatable {
 
-    @Successor private BeginNode trueSuccessor;
-    @Successor private BeginNode falseSuccessor;
+    @Successor private AbstractBeginNode trueSuccessor;
+    @Successor private AbstractBeginNode falseSuccessor;
     @Input private LogicNode condition;
     private double trueSuccessorProbability;
 
@@ -58,10 +58,10 @@
     }
 
     public IfNode(LogicNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double trueSuccessorProbability) {
-        this(condition, BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor), trueSuccessorProbability);
+        this(condition, AbstractBeginNode.begin(trueSuccessor), AbstractBeginNode.begin(falseSuccessor), trueSuccessorProbability);
     }
 
-    public IfNode(LogicNode condition, BeginNode trueSuccessor, BeginNode falseSuccessor, double trueSuccessorProbability) {
+    public IfNode(LogicNode condition, AbstractBeginNode trueSuccessor, AbstractBeginNode falseSuccessor, double trueSuccessorProbability) {
         super(StampFactory.forVoid());
         this.condition = condition;
         this.falseSuccessor = falseSuccessor;
@@ -75,7 +75,7 @@
      * 
      * @return the true successor
      */
-    public BeginNode trueSuccessor() {
+    public AbstractBeginNode trueSuccessor() {
         return trueSuccessor;
     }
 
@@ -84,16 +84,16 @@
      * 
      * @return the false successor
      */
-    public BeginNode falseSuccessor() {
+    public AbstractBeginNode falseSuccessor() {
         return falseSuccessor;
     }
 
-    public void setTrueSuccessor(BeginNode node) {
+    public void setTrueSuccessor(AbstractBeginNode node) {
         updatePredecessor(trueSuccessor, node);
         trueSuccessor = node;
     }
 
-    public void setFalseSuccessor(BeginNode node) {
+    public void setFalseSuccessor(AbstractBeginNode node) {
         updatePredecessor(falseSuccessor, node);
         falseSuccessor = node;
     }
@@ -104,14 +104,15 @@
      * @param istrue {@code true} if the true successor is requested, {@code false} otherwise
      * @return the corresponding successor
      */
-    public BeginNode successor(boolean istrue) {
+    public AbstractBeginNode successor(boolean istrue) {
         return istrue ? trueSuccessor : falseSuccessor;
     }
 
     @Override
-    public Negatable negate() {
-        BeginNode trueSucc = trueSuccessor();
-        BeginNode falseSucc = falseSuccessor();
+    public Negatable negate(LogicNode cond) {
+        assert cond == condition();
+        AbstractBeginNode trueSucc = trueSuccessor();
+        AbstractBeginNode falseSucc = falseSuccessor();
         setTrueSuccessor(null);
         setFalseSuccessor(null);
         setTrueSuccessor(falseSucc);
@@ -125,7 +126,7 @@
     }
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         return successor == trueSuccessor ? trueSuccessorProbability : 1 - trueSuccessorProbability;
     }
 
@@ -169,7 +170,7 @@
         }
 
         if (falseSuccessor().usages().isEmpty() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode) {
-            BeginNode intermediateBegin = falseSuccessor();
+            AbstractBeginNode intermediateBegin = falseSuccessor();
             IfNode nextIf = (IfNode) intermediateBegin.next();
             double probabilityB = (1.0 - this.trueSuccessorProbability) * nextIf.trueSuccessorProbability;
             if (this.trueSuccessorProbability < probabilityB) {
@@ -178,7 +179,7 @@
                 if (prepareForSwap(tool.runtime(), condition(), nextIf.condition(), this.trueSuccessorProbability, probabilityB)) {
                     // Reording is allowed from (if1 => begin => if2) to (if2 => begin => if1).
                     assert intermediateBegin.next() == nextIf;
-                    BeginNode bothFalseBegin = nextIf.falseSuccessor();
+                    AbstractBeginNode bothFalseBegin = nextIf.falseSuccessor();
                     nextIf.setFalseSuccessor(null);
                     intermediateBegin.setNext(null);
                     this.setFalseSuccessor(null);
@@ -322,9 +323,9 @@
      * @return true if a transformation was made, false otherwise
      */
     private boolean removeOrMaterializeIf(SimplifierTool tool) {
-        if (trueSuccessor().next() instanceof EndNode && falseSuccessor().next() instanceof EndNode) {
-            EndNode trueEnd = (EndNode) trueSuccessor().next();
-            EndNode falseEnd = (EndNode) falseSuccessor().next();
+        if (trueSuccessor().next() instanceof AbstractEndNode && falseSuccessor().next() instanceof AbstractEndNode) {
+            AbstractEndNode trueEnd = (AbstractEndNode) trueSuccessor().next();
+            AbstractEndNode falseEnd = (AbstractEndNode) falseSuccessor().next();
             MergeNode merge = trueEnd.merge();
             if (merge == falseEnd.merge() && merge.forwardEndCount() == 2 && trueSuccessor().anchored().isEmpty() && falseSuccessor().anchored().isEmpty()) {
                 Iterator<PhiNode> phis = merge.phis().iterator();
@@ -447,7 +448,7 @@
             }
         }
 
-        List<EndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
+        List<AbstractEndNode> mergePredecessors = merge.cfgPredecessors().snapshot();
         assert phi.valueCount() == merge.forwardEndCount();
 
         Constant[] xs = constantValues(compare.x(), merge);
@@ -461,19 +462,19 @@
             return false;
         }
 
-        List<EndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
-        List<EndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
-        Map<EndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
+        List<AbstractEndNode> falseEnds = new ArrayList<>(mergePredecessors.size());
+        List<AbstractEndNode> trueEnds = new ArrayList<>(mergePredecessors.size());
+        Map<AbstractEndNode, ValueNode> phiValues = new HashMap<>(mergePredecessors.size());
 
-        BeginNode oldFalseSuccessor = falseSuccessor();
-        BeginNode oldTrueSuccessor = trueSuccessor();
+        AbstractBeginNode oldFalseSuccessor = falseSuccessor();
+        AbstractBeginNode oldTrueSuccessor = trueSuccessor();
 
         setFalseSuccessor(null);
         setTrueSuccessor(null);
 
-        Iterator<EndNode> ends = mergePredecessors.iterator();
+        Iterator<AbstractEndNode> ends = mergePredecessors.iterator();
         for (int i = 0; i < xs.length; i++) {
-            EndNode end = ends.next();
+            AbstractEndNode end = ends.next();
             phiValues.put(end, phi.valueAt(end));
             if (compare.condition().foldCondition(xs[i], ys[i], tool.runtime(), compare.unorderedIsTrue())) {
                 trueEnds.add(end);
@@ -525,8 +526,8 @@
             } else if (node instanceof FixedWithNextNode) {
                 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) node;
                 node = fixedWithNextNode.next();
-            } else if (node instanceof EndNode) {
-                EndNode endNode = (EndNode) node;
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
                 node = endNode.merge();
             } else if (node instanceof ControlSinkNode) {
                 return true;
@@ -545,12 +546,12 @@
      * @param oldMerge the merge being removed
      * @param phiValues the values of the phi at the merge, keyed by the merge ends
      */
-    private void connectEnds(List<EndNode> ends, Map<EndNode, ValueNode> phiValues, BeginNode successor, MergeNode oldMerge, SimplifierTool tool) {
+    private void connectEnds(List<AbstractEndNode> ends, Map<AbstractEndNode, ValueNode> phiValues, AbstractBeginNode successor, MergeNode oldMerge, SimplifierTool tool) {
         if (ends.isEmpty()) {
             GraphUtil.killCFG(successor);
         } else {
             if (ends.size() == 1) {
-                EndNode end = ends.get(0);
+                AbstractEndNode end = ends.get(0);
                 ((FixedWithNextNode) end.predecessor()).setNext(successor);
                 oldMerge.removeEnd(end);
                 GraphUtil.killCFG(end);
@@ -561,7 +562,7 @@
                 PhiNode oldPhi = (PhiNode) oldMerge.usages().first();
                 PhiNode newPhi = graph().add(new PhiNode(oldPhi.stamp(), newMerge));
 
-                for (EndNode end : ends) {
+                for (AbstractEndNode end : ends) {
                     newPhi.addInput(phiValues.get(end));
                     newMerge.addForwardEnd(end);
                 }
@@ -613,12 +614,12 @@
     }
 
     private void removeEmptyIf(SimplifierTool tool) {
-        BeginNode originalTrueSuccessor = trueSuccessor();
-        BeginNode originalFalseSuccessor = falseSuccessor();
-        assert originalTrueSuccessor.next() instanceof EndNode && originalFalseSuccessor.next() instanceof EndNode;
+        AbstractBeginNode originalTrueSuccessor = trueSuccessor();
+        AbstractBeginNode originalFalseSuccessor = falseSuccessor();
+        assert originalTrueSuccessor.next() instanceof AbstractEndNode && originalFalseSuccessor.next() instanceof AbstractEndNode;
 
-        EndNode trueEnd = (EndNode) originalTrueSuccessor.next();
-        EndNode falseEnd = (EndNode) originalFalseSuccessor.next();
+        AbstractEndNode trueEnd = (AbstractEndNode) originalTrueSuccessor.next();
+        AbstractEndNode falseEnd = (AbstractEndNode) originalFalseSuccessor.next();
         assert trueEnd.merge() == falseEnd.merge();
 
         FixedWithNextNode pred = (FixedWithNextNode) predecessor();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -34,7 +34,7 @@
 @NodeInfo(nameTemplate = "Invoke!#{p#targetMethod/s}")
 public class InvokeWithExceptionNode extends ControlSplitNode implements Node.IterableNodeType, Invoke, MemoryCheckpoint, LIRLowerable {
 
-    @Successor private BeginNode next;
+    @Successor private AbstractBeginNode next;
     @Successor private DispatchBeginNode exceptionEdge;
     @Input private final CallTargetNode callTarget;
     @Input private FrameState deoptState;
@@ -61,11 +61,11 @@
         exceptionEdge = x;
     }
 
-    public BeginNode next() {
+    public AbstractBeginNode next() {
         return next;
     }
 
-    public void setNext(BeginNode x) {
+    public void setNext(AbstractBeginNode x) {
         updatePredecessor(next, x);
         next = x;
     }
@@ -121,7 +121,7 @@
     @Override
     public void setNext(FixedNode x) {
         if (x != null) {
-            this.setNext(BeginNode.begin(x));
+            this.setNext(AbstractBeginNode.begin(x));
         } else {
             this.setNext(null);
         }
@@ -170,7 +170,7 @@
     }
 
     public void killExceptionEdge() {
-        BeginNode edge = exceptionEdge();
+        AbstractBeginNode edge = exceptionEdge();
         setExceptionEdge(null);
         GraphUtil.killCFG(edge);
     }
@@ -205,7 +205,7 @@
     private static final double EXCEPTION_PROBA = 1e-5;
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         return successor == next ? 1 - EXCEPTION_PROBA : EXCEPTION_PROBA;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicBinaryNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.spi.*;
+
+public abstract class LogicBinaryNode extends LogicNode implements Negatable, Node.IterableNodeType {
+
+    @Input private LogicNode x;
+    @Input private LogicNode y;
+    private boolean xNegated;
+    private boolean yNegated;
+
+    public LogicBinaryNode(LogicNode x, LogicNode y) {
+        this(x, false, y, false);
+    }
+
+    public LogicBinaryNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) {
+        this.x = x;
+        this.xNegated = xNegated;
+        this.y = y;
+        this.yNegated = yNegated;
+    }
+
+    public LogicNode getX() {
+        return x;
+    }
+
+    public LogicNode getY() {
+        return y;
+    }
+
+    public boolean isXNegated() {
+        return xNegated;
+    }
+
+    public boolean isYNegated() {
+        return yNegated;
+    }
+
+    @Override
+    public Negatable negate(LogicNode condition) {
+        if (condition == x) {
+            xNegated = !xNegated;
+        }
+        if (condition == y) {
+            yNegated = !yNegated;
+        }
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicConjunctionNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This node is true if {@link #getX() x} <b>and</b> {@link #getY() y} are true.
+ * 
+ */
+public class LogicConjunctionNode extends LogicBinaryNode implements Canonicalizable {
+
+    public LogicConjunctionNode(LogicNode x, LogicNode y) {
+        this(x, false, y, false);
+    }
+
+    public LogicConjunctionNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) {
+        super(x, xNegated, y, yNegated);
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool) {
+        LogicNode x = getX();
+        LogicNode y = getY();
+        if (x == y) {
+            return x;
+        }
+        if (x instanceof LogicConstantNode) {
+            if (((LogicConstantNode) x).getValue() ^ isXNegated()) {
+                if (isYNegated()) {
+                    negateUsages();
+                }
+                return y;
+            } else {
+                return LogicConstantNode.contradiction(graph());
+            }
+        }
+        if (y instanceof LogicConstantNode) {
+            if (((LogicConstantNode) y).getValue() ^ isYNegated()) {
+                if (isXNegated()) {
+                    negateUsages();
+                }
+                return x;
+            } else {
+                return LogicConstantNode.contradiction(graph());
+            }
+        }
+        return this;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicDisjunctionNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.nodes.spi.*;
+
+/**
+ * This node is true if {@link #getX() x} <b>or</b> {@link #getY() y} are true.
+ * 
+ */
+public class LogicDisjunctionNode extends LogicBinaryNode implements Canonicalizable {
+
+    public LogicDisjunctionNode(LogicNode x, LogicNode y) {
+        this(x, false, y, false);
+    }
+
+    public LogicDisjunctionNode(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated) {
+        super(x, xNegated, y, yNegated);
+    }
+
+    @Override
+    public LogicNode canonical(CanonicalizerTool tool) {
+        LogicNode x = getX();
+        LogicNode y = getY();
+        if (x == y) {
+            return x;
+        }
+        if (x instanceof LogicConstantNode) {
+            if (((LogicConstantNode) x).getValue() ^ isXNegated()) {
+                return LogicConstantNode.tautology(graph());
+            } else {
+                if (isYNegated()) {
+                    negateUsages();
+                }
+                return y;
+            }
+        }
+        if (y instanceof LogicConstantNode) {
+            if (((LogicConstantNode) y).getValue() ^ isYNegated()) {
+                return LogicConstantNode.tautology(graph());
+            } else {
+                if (isXNegated()) {
+                    negateUsages();
+                }
+                return x;
+            }
+        }
+        return this;
+    }
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LogicNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -40,7 +40,7 @@
     public void negateUsages() {
         for (Node n : usages().snapshot()) {
             assert n instanceof Negatable;
-            ((Negatable) n).negate();
+            ((Negatable) n).negate(this);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopBeginNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -87,7 +87,7 @@
         return snapshot;
     }
 
-    public EndNode forwardEnd() {
+    public AbstractEndNode forwardEnd() {
         assert forwardEndCount() == 1;
         return forwardEndAt(0);
     }
@@ -98,7 +98,7 @@
     }
 
     @Override
-    protected void deleteEnd(EndNode end) {
+    protected void deleteEnd(AbstractEndNode end) {
         if (end instanceof LoopEndNode) {
             LoopEndNode loopEnd = (LoopEndNode) end;
             loopEnd.setLoopBegin(null);
@@ -122,7 +122,7 @@
     }
 
     @Override
-    public int phiPredecessorIndex(EndNode pred) {
+    public int phiPredecessorIndex(AbstractEndNode pred) {
         if (pred instanceof LoopEndNode) {
             LoopEndNode loopEnd = (LoopEndNode) pred;
             if (loopEnd.loopBegin() == this) {
@@ -136,7 +136,7 @@
     }
 
     @Override
-    public EndNode phiPredecessorAt(int index) {
+    public AbstractEndNode phiPredecessorAt(int index) {
         if (index < forwardEndCount()) {
             return forwardEndAt(index);
         }
@@ -173,7 +173,7 @@
         // nothing yet
     }
 
-    public boolean isLoopExit(BeginNode begin) {
+    public boolean isLoopExit(AbstractBeginNode begin) {
         return begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopEndNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 
-public final class LoopEndNode extends EndNode {
+public final class LoopEndNode extends AbstractEndNode {
 
     @Input(notDataflow = true) private LoopBeginNode loopBegin;
     private boolean canSafepoint;
@@ -60,9 +60,6 @@
     }
 
     public boolean canSafepoint() {
-        if (!canSafepoint) {
-            return canSafepoint;
-        }
         return canSafepoint;
     }
 
@@ -81,7 +78,7 @@
 
     /**
      * Returns the 0-based index of this loop end. This is <b>not</b> the index into {@link PhiNode}
-     * values at the loop begin. Use {@link MergeNode#phiPredecessorIndex(EndNode)} for this
+     * values at the loop begin. Use {@link MergeNode#phiPredecessorIndex(AbstractEndNode)} for this
      * purpose.
      * 
      * @return The 0-based index of this loop end.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -35,18 +35,18 @@
  */
 public class MergeNode extends BeginStateSplitNode implements Node.IterableNodeType, LIRLowerable {
 
-    @Input(notDataflow = true) private final NodeInputList<EndNode> ends = new NodeInputList<>(this);
+    @Input(notDataflow = true) private final NodeInputList<AbstractEndNode> ends = new NodeInputList<>(this);
 
     @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitMerge(this);
     }
 
-    public int forwardEndIndex(EndNode end) {
+    public int forwardEndIndex(AbstractEndNode end) {
         return ends.indexOf(end);
     }
 
-    public void addForwardEnd(EndNode end) {
+    public void addForwardEnd(AbstractEndNode end) {
         ends.add(end);
     }
 
@@ -54,12 +54,12 @@
         return ends.size();
     }
 
-    public EndNode forwardEndAt(int index) {
+    public AbstractEndNode forwardEndAt(int index) {
         return ends.get(index);
     }
 
     @Override
-    public NodeIterable<EndNode> cfgPredecessors() {
+    public NodeIterable<AbstractEndNode> cfgPredecessors() {
         return ends;
     }
 
@@ -79,7 +79,7 @@
      * 
      * @param pred the end to remove
      */
-    public void removeEnd(EndNode pred) {
+    public void removeEnd(AbstractEndNode pred) {
         int predIndex = phiPredecessorIndex(pred);
         assert predIndex != -1;
         deleteEnd(pred);
@@ -95,7 +95,7 @@
         }
     }
 
-    protected void deleteEnd(EndNode end) {
+    protected void deleteEnd(AbstractEndNode end) {
         ends.remove(end);
     }
 
@@ -103,7 +103,7 @@
         ends.clear();
     }
 
-    public NodeIterable<EndNode> forwardEnds() {
+    public NodeIterable<AbstractEndNode> forwardEnds() {
         return ends;
     }
 
@@ -111,11 +111,11 @@
         return forwardEndCount();
     }
 
-    public int phiPredecessorIndex(EndNode pred) {
+    public int phiPredecessorIndex(AbstractEndNode pred) {
         return forwardEndIndex(pred);
     }
 
-    public EndNode phiPredecessorAt(int index) {
+    public AbstractEndNode phiPredecessorAt(int index) {
         return forwardEndAt(index);
     }
 
@@ -143,8 +143,8 @@
     @Override
     public void simplify(SimplifierTool tool) {
         FixedNode next = next();
-        if (next instanceof EndNode) {
-            EndNode origLoopEnd = (EndNode) next;
+        if (next instanceof AbstractEndNode) {
+            AbstractEndNode origLoopEnd = (AbstractEndNode) next;
             MergeNode merge = origLoopEnd.merge();
             if (merge instanceof LoopBeginNode && !(origLoopEnd instanceof LoopEndNode)) {
                 return;
@@ -169,8 +169,8 @@
             int numEnds = this.forwardEndCount();
             StructuredGraph graph = (StructuredGraph) graph();
             for (int i = 0; i < numEnds - 1; i++) {
-                EndNode end = forwardEndAt(numEnds - 1 - i);
-                EndNode newEnd;
+                AbstractEndNode end = forwardEndAt(numEnds - 1 - i);
+                AbstractEndNode newEnd;
                 if (merge instanceof LoopBeginNode) {
                     newEnd = graph.add(new LoopEndNode((LoopBeginNode) merge));
                 } else {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PhiNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -159,7 +159,7 @@
         values.set(i, x);
     }
 
-    public ValueNode valueAt(EndNode pred) {
+    public ValueNode valueAt(AbstractEndNode pred) {
         return valueAt(merge().phiPredecessorIndex(pred));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ProxyNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -37,12 +37,12 @@
 @NodeInfo(nameTemplate = "{p#type/s}Proxy")
 public class ProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable, Canonicalizable, Virtualizable, LIRLowerable {
 
-    @Input(notDataflow = true) private BeginNode proxyPoint;
+    @Input(notDataflow = true) private AbstractBeginNode proxyPoint;
     @Input private ValueNode value;
     private final PhiType type;
     private final Object identity;
 
-    public ProxyNode(ValueNode value, BeginNode exit, PhiType type, Object identity) {
+    public ProxyNode(ValueNode value, AbstractBeginNode exit, PhiType type, Object identity) {
         super(type == PhiType.Value ? value.stamp() : type.stamp);
         this.type = type;
         this.identity = identity;
@@ -65,7 +65,7 @@
         return value().stamp();
     }
 
-    public BeginNode proxyPoint() {
+    public AbstractBeginNode proxyPoint() {
         return proxyPoint;
     }
 
@@ -108,11 +108,11 @@
         }
     }
 
-    public static ProxyNode forValue(ValueNode value, BeginNode exit, StructuredGraph graph) {
+    public static ProxyNode forValue(ValueNode value, AbstractBeginNode exit, StructuredGraph graph) {
         return graph.unique(new ProxyNode(value, exit, PhiType.Value, null));
     }
 
-    public static ProxyNode forMemory(ValueNode value, BeginNode exit, Object location, StructuredGraph graph) {
+    public static ProxyNode forMemory(ValueNode value, AbstractBeginNode exit, Object location, StructuredGraph graph) {
         return graph.unique(new ProxyNode(value, exit, PhiType.Memory, location));
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Tue Apr 30 22:22:42 2013 +0200
@@ -50,14 +50,14 @@
     private final int entryBCI;
 
     /**
-     * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
+     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start() start} node.
      */
     public StructuredGraph() {
         this(null, null);
     }
 
     /**
-     * Creates a new Graph containing a single {@link BeginNode} as the {@link #start() start} node.
+     * Creates a new Graph containing a single {@link AbstractBeginNode} as the {@link #start() start} node.
      */
     public StructuredGraph(String name, ResolvedJavaMethod method) {
         this(name, method, uniqueGraphIds.incrementAndGet(), INVOCATION_ENTRY_BCI);
@@ -214,8 +214,8 @@
      */
     public void removeFixed(FixedWithNextNode node) {
         assert node != null;
-        if (node instanceof BeginNode) {
-            ((BeginNode) node).prepareDelete();
+        if (node instanceof AbstractBeginNode) {
+            ((AbstractBeginNode) node).prepareDelete();
         }
         assert node.usages().isEmpty() : node + " " + node.usages();
         FixedNode next = node.next();
@@ -251,7 +251,7 @@
         node.safeDelete();
     }
 
-    public void removeSplit(ControlSplitNode node, BeginNode survivingSuccessor) {
+    public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
         assert node != null;
         assert node.usages().isEmpty();
         assert survivingSuccessor != null;
@@ -260,7 +260,7 @@
         node.safeDelete();
     }
 
-    public void removeSplitPropagate(ControlSplitNode node, BeginNode survivingSuccessor) {
+    public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) {
         assert node != null;
         assert node.usages().isEmpty();
         assert survivingSuccessor != null;
@@ -271,13 +271,13 @@
         for (Node successor : snapshot) {
             if (successor != null && successor.isAlive()) {
                 if (successor != survivingSuccessor) {
-                    GraphUtil.killCFG((BeginNode) successor);
+                    GraphUtil.killCFG((AbstractBeginNode) successor);
                 }
             }
         }
     }
 
-    public void replaceSplit(ControlSplitNode node, Node replacement, BeginNode survivingSuccessor) {
+    public void replaceSplit(ControlSplitNode node, Node replacement, AbstractBeginNode survivingSuccessor) {
         if (replacement instanceof FixedWithNextNode) {
             replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor);
         } else {
@@ -287,7 +287,7 @@
         }
     }
 
-    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, BeginNode survivingSuccessor) {
+    public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, AbstractBeginNode survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         assert survivingSuccessor != null;
         node.clearSuccessors();
@@ -295,7 +295,7 @@
         node.replaceAndDelete(replacement);
     }
 
-    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, BeginNode survivingSuccessor) {
+    public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, AbstractBeginNode survivingSuccessor) {
         assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement;
         assert survivingSuccessor != null;
         node.clearSuccessors();
@@ -348,7 +348,7 @@
         if (merge instanceof LoopBeginNode) {
             ((LoopBeginNode) merge).removeExits();
         }
-        EndNode singleEnd = merge.forwardEndAt(0);
+        AbstractEndNode singleEnd = merge.forwardEndAt(0);
         FixedNode sux = merge.next();
         FrameState stateAfter = merge.stateAfter();
         // evacuateGuards
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -101,6 +101,16 @@
         return this;
     }
 
+    protected void setX(ValueNode x) {
+        updateUsages(this.x, x);
+        this.x = x;
+    }
+
+    protected void setY(ValueNode y) {
+        updateUsages(this.y, y);
+        this.y = y;
+    }
+
     protected LogicNode optimizeNormalizeCmp(Constant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
         throw new GraalInternalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
     }
@@ -123,6 +133,14 @@
                 return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false);
             }
         }
+        if (x() instanceof ConvertNode && y() instanceof ConvertNode) {
+            ConvertNode convertX = (ConvertNode) x();
+            ConvertNode convertY = (ConvertNode) y();
+            if (convertX.opcode.isLossless() && convertY.opcode.isLossless()) {
+                setX(convertX.value());
+                setY(convertY.value());
+            }
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -94,7 +94,8 @@
     }
 
     @Override
-    public Negatable negate() {
+    public Negatable negate(LogicNode cond) {
+        assert condition() == cond;
         ConditionalNode replacement = graph().unique(new ConditionalNode(condition, falseValue(), trueValue()));
         ((StructuredGraph) graph()).replaceFloating(this, replacement);
         return replacement;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConvertNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -25,6 +25,7 @@
 import static com.oracle.graal.api.meta.Kind.*;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
@@ -34,34 +35,97 @@
  */
 public final class ConvertNode extends FloatingNode implements Canonicalizable, LIRLowerable, Lowerable {
 
-    public enum Op {
-        I2L(Int, Long),
-        L2I(Long, Int),
-        I2B(Int, Byte),
-        I2C(Int, Char),
-        I2S(Int, Short),
-        F2D(Float, Double),
-        D2F(Double, Float),
-        I2F(Int, Float),
-        I2D(Int, Double),
-        F2I(Float, Int),
-        D2I(Double, Int),
-        L2F(Long, Float),
-        L2D(Long, Double),
-        F2L(Float, Long),
-        D2L(Double, Long),
-        UNSIGNED_I2L(Int, Long),
-        MOV_I2F(Int, Float),
-        MOV_L2D(Long, Double),
-        MOV_F2I(Float, Int),
-        MOV_D2L(Double, Long);
+    public static enum Op {
+        I2L(Int, Long, true),
+        L2I(Long, Int, false),
+        I2B(Int, Byte, false),
+        I2C(Int, Char, false),
+        I2S(Int, Short, false),
+        F2D(Float, Double, false),
+        D2F(Double, Float, false),
+        I2F(Int, Float, false),
+        I2D(Int, Double, true),
+        F2I(Float, Int, false),
+        D2I(Double, Int, false),
+        L2F(Long, Float, false),
+        L2D(Long, Double, false),
+        F2L(Float, Long, false),
+        D2L(Double, Long, false),
+        UNSIGNED_I2L(Int, Long, true),
+        MOV_I2F(Int, Float, false),
+        MOV_L2D(Long, Double, false),
+        MOV_F2I(Float, Int, false),
+        MOV_D2L(Double, Long, false);
 
         public final Kind from;
         public final Kind to;
+        public final boolean lossless;
 
-        private Op(Kind from, Kind to) {
+        private Op(Kind from, Kind to, boolean lossless) {
             this.from = from;
             this.to = to;
+            this.lossless = lossless;
+        }
+
+        public boolean isLossless() {
+            return lossless;
+        }
+
+        public static Op getOp(Kind from, Kind to) {
+            switch (from) {
+                case Int:
+                    switch (to) {
+                        case Byte:
+                            return I2B;
+                        case Char:
+                            return I2C;
+                        case Short:
+                            return I2S;
+                        case Long:
+                            return I2L;
+                        case Float:
+                            return I2F;
+                        case Double:
+                            return I2D;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case Long:
+                    switch (to) {
+                        case Int:
+                            return L2I;
+                        case Float:
+                            return L2F;
+                        case Double:
+                            return L2D;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case Float:
+                    switch (to) {
+                        case Int:
+                            return F2I;
+                        case Long:
+                            return F2L;
+                        case Double:
+                            return F2D;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                case Double:
+                    switch (to) {
+                        case Int:
+                            return D2I;
+                        case Long:
+                            return D2L;
+                        case Float:
+                            return D2F;
+                        default:
+                            throw GraalInternalError.shouldNotReachHere();
+                    }
+                default:
+                    throw GraalInternalError.shouldNotReachHere();
+            }
         }
     }
 
@@ -171,6 +235,14 @@
         gen.setResult(this, gen.emitConvert(opcode, gen.operand(value())));
     }
 
+    public static ValueNode convert(Kind toKind, ValueNode value) {
+        Kind fromKind = value.kind();
+        if (fromKind == toKind) {
+            return value;
+        }
+        return value.graph().unique(new ConvertNode(Op.getOp(fromKind, toKind), value));
+    }
+
     @NodeIntrinsic
     public static native float convert(@ConstantNodeParameter Op op, int value);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerDivNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -99,6 +99,13 @@
             }
         }
 
+        if (next() instanceof IntegerDivNode) {
+            NodeClass nodeClass = NodeClass.get(this.getClass());
+            if (next().getClass() == this.getClass() && nodeClass.inputsEqual(this, next()) && nodeClass.valueEqual(this, next())) {
+                return next();
+            }
+        }
+
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -69,6 +69,10 @@
         if (x() instanceof NegateNode) {
             return ((NegateNode) x()).x();
         }
+        if (x() instanceof IntegerSubNode) {
+            IntegerSubNode sub = (IntegerSubNode) x;
+            return IntegerArithmeticNode.sub(sub.y(), sub.x());
+        }
         return this;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java	Tue Apr 30 22:22:42 2013 +0200
@@ -29,7 +29,7 @@
 
 public final class Block {
 
-    protected final BeginNode beginNode;
+    protected final AbstractBeginNode beginNode;
 
     protected int id;
 
@@ -46,7 +46,7 @@
     private boolean align;
     private int linearScanNumber;
 
-    protected Block(BeginNode node) {
+    protected Block(AbstractBeginNode node) {
         this.beginNode = node;
 
         this.id = ControlFlowGraph.BLOCK_ID_INITIAL;
@@ -57,7 +57,7 @@
         return id;
     }
 
-    public BeginNode getBeginNode() {
+    public AbstractBeginNode getBeginNode() {
         return beginNode;
     }
 
@@ -150,7 +150,7 @@
             } else {
                 cur = ((FixedWithNextNode) cur).next();
             }
-            assert !(cur instanceof BeginNode);
+            assert !(cur instanceof AbstractBeginNode);
             return result;
         }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java	Tue Apr 30 22:22:42 2013 +0200
@@ -58,7 +58,7 @@
 
     protected ControlFlowGraph(StructuredGraph graph) {
         this.graph = graph;
-        this.nodeToBlock = graph.createNodeMap();
+        this.nodeToBlock = graph.createNodeMap(true);
     }
 
     public Block[] getBlocks() {
@@ -135,7 +135,7 @@
 
             last = cur;
             cur = cur.successors().first();
-        } while (cur != null && !(cur instanceof BeginNode));
+        } while (cur != null && !(cur instanceof AbstractBeginNode));
 
         block.endNode = (FixedNode) last;
     }
@@ -144,8 +144,8 @@
         // Find all block headers
         int numBlocks = 0;
         for (Node node : graph.getNodes()) {
-            if (node instanceof BeginNode) {
-                Block block = new Block((BeginNode) node);
+            if (node instanceof AbstractBeginNode) {
+                Block block = new Block((AbstractBeginNode) node);
                 numBlocks++;
                 identifyBlock(block);
             }
@@ -247,7 +247,7 @@
                 for (Block b : loop.blocks) {
                     for (Block sux : b.getSuccessors()) {
                         if (sux.loop != loop) {
-                            BeginNode begin = sux.getBeginNode();
+                            AbstractBeginNode begin = sux.getBeginNode();
                             if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) {
                                 Debug.log("Unexpected loop exit with %s, including whole branch in the loop", sux);
                                 unexpected.add(sux);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/IntegerSwitchNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -48,7 +48,7 @@
      * @param keyProbabilities the probabilities of the keys
      * @param keySuccessors the successor index for each key
      */
-    public IntegerSwitchNode(ValueNode value, BeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    public IntegerSwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
         super(value, successors, keySuccessors, keyProbabilities);
         assert keySuccessors.length == keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
@@ -66,7 +66,7 @@
      * @param keySuccessors the successor index for each key
      */
     public IntegerSwitchNode(ValueNode value, int successorCount, int[] keys, double[] keyProbabilities, int[] keySuccessors) {
-        this(value, new BeginNode[successorCount], keys, keyProbabilities, keySuccessors);
+        this(value, new AbstractBeginNode[successorCount], keys, keyProbabilities, keySuccessors);
     }
 
     /**
@@ -124,7 +124,7 @@
                     tool.addToWorkList(defaultSuccessor());
                     ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
                 } else if (validKeys != keys.length) {
-                    ArrayList<BeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+                    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
                     int[] newKeys = new int[validKeys];
                     int[] newKeySuccessors = new int[validKeys + 1];
                     double[] newKeyProbabilities = new double[validKeys + 1];
@@ -153,14 +153,14 @@
                     }
 
                     for (int i = 0; i < blockSuccessorCount(); i++) {
-                        BeginNode successor = blockSuccessor(i);
+                        AbstractBeginNode successor = blockSuccessor(i);
                         if (!newSuccessors.contains(successor)) {
                             tool.deleteBranch(successor);
                         }
                         setBlockSuccessor(i, null);
                     }
 
-                    BeginNode[] successorsArray = newSuccessors.toArray(new BeginNode[newSuccessors.size()]);
+                    AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
                     IntegerSwitchNode newSwitch = graph().add(new IntegerSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
                     ((FixedWithNextNode) predecessor()).setNext(newSwitch);
                     GraphUtil.killWithUnusedFloatingInputs(this);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SwitchNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -34,7 +34,7 @@
  */
 public abstract class SwitchNode extends ControlSplitNode {
 
-    @Successor protected final NodeSuccessorList<BeginNode> successors;
+    @Successor protected final NodeSuccessorList<AbstractBeginNode> successors;
     @Input private ValueNode value;
     private double[] keyProbabilities;
     private int[] keySuccessors;
@@ -45,7 +45,7 @@
      * @param value the instruction that provides the value to be switched over
      * @param successors the list of successors of this switch
      */
-    public SwitchNode(ValueNode value, BeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
+    public SwitchNode(ValueNode value, AbstractBeginNode[] successors, int[] keySuccessors, double[] keyProbabilities) {
         super(StampFactory.forVoid());
         assert keySuccessors.length == keyProbabilities.length;
         this.successors = new NodeSuccessorList<>(this, successors);
@@ -55,7 +55,7 @@
     }
 
     @Override
-    public double probability(BeginNode successor) {
+    public double probability(AbstractBeginNode successor) {
         double sum = 0;
         for (int i = 0; i < keySuccessors.length; i++) {
             if (successors.get(keySuccessors[i]) == successor) {
@@ -89,7 +89,7 @@
     /**
      * Returns the successor for the key at the given index.
      */
-    public BeginNode keySuccessor(int i) {
+    public AbstractBeginNode keySuccessor(int i) {
         return successors.get(keySuccessors[i]);
     }
 
@@ -107,11 +107,11 @@
         return keySuccessors[keySuccessors.length - 1];
     }
 
-    public BeginNode blockSuccessor(int i) {
+    public AbstractBeginNode blockSuccessor(int i) {
         return successors.get(i);
     }
 
-    public void setBlockSuccessor(int i, BeginNode s) {
+    public void setBlockSuccessor(int i, AbstractBeginNode s) {
         successors.set(i, s);
     }
 
@@ -124,7 +124,7 @@
      * 
      * @return the default successor
      */
-    public BeginNode defaultSuccessor() {
+    public AbstractBeginNode defaultSuccessor() {
         if (defaultSuccessorIndex() == -1) {
             throw new GraalInternalError("unexpected");
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -100,7 +100,7 @@
         if (permanent) {
             return;
         }
-        for (ValueNode node : dependencies().nonNull().and(isNotA(BeginNode.class))) {
+        for (ValueNode node : dependencies().nonNull().and(isNotA(AbstractBeginNode.class))) {
             State state = tool.getObjectState(node);
             if (state == null || state.getState() != EscapeState.Virtual) {
                 return;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeSwitchNode.java	Tue Apr 30 22:22:42 2013 +0200
@@ -50,7 +50,7 @@
      * @param keyProbabilities the probabilities of the keys
      * @param keySuccessors the successor index for each key
      */
-    public TypeSwitchNode(ValueNode value, BeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
+    public TypeSwitchNode(ValueNode value, AbstractBeginNode[] successors, ResolvedJavaType[] keys, double[] keyProbabilities, int[] keySuccessors) {
         super(value, successors, keySuccessors, keyProbabilities);
         assert successors.length <= keys.length + 1;
         assert keySuccessors.length == keyProbabilities.length;
@@ -110,7 +110,7 @@
                     tool.addToWorkList(defaultSuccessor());
                     ((StructuredGraph) graph()).removeSplitPropagate(this, defaultSuccessor());
                 } else if (validKeys != keys.length) {
-                    ArrayList<BeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
+                    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
                     ResolvedJavaType[] newKeys = new ResolvedJavaType[validKeys];
                     int[] newKeySuccessors = new int[validKeys + 1];
                     double[] newKeyProbabilities = new double[validKeys + 1];
@@ -139,14 +139,14 @@
                     }
 
                     for (int i = 0; i < blockSuccessorCount(); i++) {
-                        BeginNode successor = blockSuccessor(i);
+                        AbstractBeginNode successor = blockSuccessor(i);
                         if (!newSuccessors.contains(successor)) {
                             tool.deleteBranch(successor);
                         }
                         setBlockSuccessor(i, null);
                     }
 
-                    BeginNode[] successorsArray = newSuccessors.toArray(new BeginNode[newSuccessors.size()]);
+                    AbstractBeginNode[] successorsArray = newSuccessors.toArray(new AbstractBeginNode[newSuccessors.size()]);
                     TypeSwitchNode newSwitch = graph().add(new TypeSwitchNode(value(), successorsArray, newKeys, newKeyProbabilities, newKeySuccessors));
                     ((FixedWithNextNode) predecessor()).setNext(newSwitch);
                     GraphUtil.killWithUnusedFloatingInputs(this);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Tue Apr 30 22:22:42 2013 +0200
@@ -116,7 +116,7 @@
     // Handling of block-end nodes still needs to be unified in the LIRGenerator.
     void visitMerge(MergeNode i);
 
-    void visitEndNode(EndNode i);
+    void visitEndNode(AbstractEndNode i);
 
     void visitLoopEnd(LoopEndNode i);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Tue Apr 30 22:22:42 2013 +0200
@@ -28,15 +28,15 @@
  * This interface marks a node as being able to negate its effect, this is intended for nodes that
  * depend on a BooleanNode condition. The canonical representation of has, for example, no way to
  * represent a != b. If such an expression appears during canonicalization the negated expression
- * will be created (a == b) and the usages will be negated, using this interface's {@link #negate()}
- * method.
+ * will be created (a == b) and the usages will be negated, using this interface's
+ * {@link #negate(LogicNode)} method.
  */
 public interface Negatable {
 
     /**
      * Tells this node that a condition it depends has been negated, and that it thus needs to
-     * invert its own effect. For example, an {@link IfNode} would switch its true and false
-     * successors.
+     * invert the effects of this condition. For example, an {@link IfNode} would switch its true
+     * and false successors.
      */
-    Negatable negate();
+    Negatable negate(LogicNode condition);
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/ComputeImmediateDominator.java	Tue Apr 30 22:22:42 2013 +0200
@@ -147,7 +147,7 @@
 
     private void processMerge(MergeNode merge, DominatorInfo info) {
         // TTY.println("processMerge(" + merge + ", " + info + ")");
-        for (EndNode end : merge.cfgPredecessors()) {
+        for (AbstractEndNode end : merge.cfgPredecessors()) {
             toExplore.add(end);
             infoMap.set(end, info.createChild(end));
             // TTY.println("  Enqueue end : " + end + " with " + infoMap.get(end));
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Tue Apr 30 22:22:42 2013 +0200
@@ -44,9 +44,9 @@
 
     public static void killCFG(FixedNode node) {
         assert node.isAlive();
-        if (node instanceof EndNode) {
+        if (node instanceof AbstractEndNode) {
             // We reached a control flow end.
-            EndNode end = (EndNode) node;
+            AbstractEndNode end = (AbstractEndNode) node;
             killEnd(end);
         } else {
             // Normal control flow node.
@@ -63,7 +63,7 @@
         propagateKill(node);
     }
 
-    private static void killEnd(EndNode end) {
+    private static void killEnd(AbstractEndNode end) {
         MergeNode merge = end.merge();
         if (merge != null) {
             merge.removeEnd(end);
@@ -152,7 +152,7 @@
     }
 
     public static void checkRedundantProxy(ProxyNode vpn) {
-        BeginNode proxyPoint = vpn.proxyPoint();
+        AbstractBeginNode proxyPoint = vpn.proxyPoint();
         if (proxyPoint instanceof LoopExitNode) {
             LoopExitNode exit = (LoopExitNode) proxyPoint;
             LoopBeginNode loopBegin = exit.loopBegin();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -213,7 +213,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
         }
 
         @Override
@@ -355,7 +355,7 @@
             }
         }
 
-        private void registerControlSplitInfo(Node pred, BeginNode begin) {
+        private void registerControlSplitInfo(Node pred, AbstractBeginNode begin) {
             assert pred != null && begin != null;
 
             if (pred instanceof IfNode) {
@@ -461,8 +461,8 @@
 
         @Override
         protected void node(FixedNode node) {
-            if (node instanceof BeginNode) {
-                BeginNode begin = (BeginNode) node;
+            if (node instanceof AbstractBeginNode) {
+                AbstractBeginNode begin = (AbstractBeginNode) node;
                 Node pred = node.predecessor();
 
                 if (pred != null) {
@@ -501,8 +501,8 @@
                         GraphUtil.killWithUnusedFloatingInputs(compare);
                     }
                 }
-            } else if (node instanceof EndNode) {
-                EndNode endNode = (EndNode) node;
+            } else if (node instanceof AbstractEndNode) {
+                AbstractEndNode endNode = (AbstractEndNode) node;
                 for (PhiNode phi : endNode.merge().phis()) {
                     int index = endNode.merge().phiPredecessorIndex(endNode);
                     ValueNode value = phi.valueAt(index);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -32,11 +32,11 @@
 
 public class ConvertDeoptimizeToGuardPhase extends Phase {
 
-    private static BeginNode findBeginNode(Node startNode) {
+    private static AbstractBeginNode findBeginNode(Node startNode) {
         Node n = startNode;
         while (true) {
-            if (n instanceof BeginNode) {
-                return (BeginNode) n;
+            if (n instanceof AbstractBeginNode) {
+                return (AbstractBeginNode) n;
             } else {
                 n = n.predecessor();
             }
@@ -57,17 +57,17 @@
         new DeadCodeEliminationPhase().apply(graph);
     }
 
-    private void visitDeoptBegin(BeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) {
+    private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizeNode deopt, StructuredGraph graph) {
         if (deoptBegin instanceof MergeNode) {
             MergeNode mergeNode = (MergeNode) deoptBegin;
             Debug.log("Visiting %s followed by %s", mergeNode, deopt);
-            List<BeginNode> begins = new ArrayList<>();
-            for (EndNode end : mergeNode.forwardEnds()) {
-                BeginNode newBeginNode = findBeginNode(end);
+            List<AbstractBeginNode> begins = new ArrayList<>();
+            for (AbstractEndNode end : mergeNode.forwardEnds()) {
+                AbstractBeginNode newBeginNode = findBeginNode(end);
                 assert !begins.contains(newBeginNode);
                 begins.add(newBeginNode);
             }
-            for (BeginNode begin : begins) {
+            for (AbstractBeginNode begin : begins) {
                 assert !begin.isDeleted();
                 visitDeoptBegin(begin, deopt, graph);
             }
@@ -75,7 +75,7 @@
             return;
         } else if (deoptBegin.predecessor() instanceof IfNode) {
             IfNode ifNode = (IfNode) deoptBegin.predecessor();
-            BeginNode otherBegin = ifNode.trueSuccessor();
+            AbstractBeginNode otherBegin = ifNode.trueSuccessor();
             LogicNode conditionNode = ifNode.condition();
             FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deoptBegin == ifNode.trueSuccessor()));
             FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CullFrameStatesPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -90,7 +90,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/DeadCodeEliminationPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -52,8 +52,8 @@
 
     private static void iterateSuccessors(NodeFlood flood) {
         for (Node current : flood) {
-            if (current instanceof EndNode) {
-                EndNode end = (EndNode) current;
+            if (current instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) current;
                 flood.add(end.merge());
             } else {
                 for (Node successor : current.successors()) {
@@ -64,7 +64,7 @@
     }
 
     private static void disconnectCFGNodes(NodeFlood flood, StructuredGraph graph) {
-        for (EndNode node : graph.getNodes(EndNode.class)) {
+        for (AbstractEndNode node : graph.getNodes(AbstractEndNode.class)) {
             if (!flood.isMarked(node)) {
                 MergeNode merge = node.merge();
                 if (merge != null && flood.isMarked(merge)) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/EliminatePartiallyRedundantGuardsPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -119,8 +119,8 @@
             if (guard.dependencies().size() != 1) {
                 continue;
             }
-            for (EndNode end : merge.forwardEnds()) {
-                BeginNode begin = BeginNode.prevBegin(end);
+            for (AbstractEndNode end : merge.forwardEnds()) {
+                AbstractBeginNode begin = AbstractBeginNode.prevBegin(end);
                 boolean found = false;
                 for (GuardNode predecessorGuard : begin.guards()) {
                     if (predecessorGuard.dependencies().size() != 1) {
@@ -140,8 +140,8 @@
         Graph graph = merge.graph();
         for (GuardNode guard : hits) {
             PhiNode phi = graph.add(new PhiNode(PhiType.Guard, merge, null));
-            for (EndNode otherEnd : merge.forwardEnds()) {
-                phi.addInput(graph.unique(new GuardNode(guard.condition(), BeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated())));
+            for (AbstractEndNode otherEnd : merge.forwardEnds()) {
+                phi.addInput(graph.unique(new GuardNode(guard.condition(), AbstractBeginNode.prevBegin(otherEnd), guard.reason(), guard.action(), guard.negated())));
             }
             guard.replaceAndDelete(phi);
             metricPRGuardsEliminatedAtMerge.increment();
@@ -152,7 +152,7 @@
     private static boolean eliminateAtControlSplit(ControlSplitNode controlSplit) {
         Map<Condition, Collection<GuardNode>> conditionToGuard = new HashMap<>();
         for (Node successor : controlSplit.successors()) {
-            BeginNode begin = (BeginNode) successor;
+            AbstractBeginNode begin = (AbstractBeginNode) successor;
             for (GuardNode guard : begin.guards()) {
                 if (guard.dependencies().size() != 1) {
                     continue;
@@ -175,9 +175,9 @@
             }
             DeoptimizationReason reason = null;
             DeoptimizationAction action = DeoptimizationAction.None;
-            Set<BeginNode> begins = new HashSet<>(3);
+            Set<AbstractBeginNode> begins = new HashSet<>(3);
             for (GuardNode guard : guards) {
-                BeginNode begin = (BeginNode) guard.dependencies().first();
+                AbstractBeginNode begin = (AbstractBeginNode) guard.dependencies().first();
                 begins.add(begin);
                 if (guard.action().ordinal() > action.ordinal()) {
                     action = guard.action();
@@ -191,7 +191,7 @@
             if (begins.size() == controlSplit.successors().count()) {
                 hits = true;
                 Condition condition = entry.getKey();
-                GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, BeginNode.prevBegin(controlSplit), reason, action, condition.negated));
+                GuardNode newGuard = controlSplit.graph().unique(new GuardNode(condition.conditionNode, AbstractBeginNode.prevBegin(controlSplit), reason, action, condition.negated));
                 for (GuardNode guard : guards) {
                     guard.replaceAndDelete(newGuard);
                     metricPRGuardsEliminatedAtSplit.increment();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ExpandLogicPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.common;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.phases.*;
+
+public class ExpandLogicPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (LogicBinaryNode logic : graph.getNodes(LogicBinaryNode.class)) {
+            processBinary(logic);
+        }
+    }
+
+    private static void processBinary(LogicBinaryNode binary) {
+        while (binary.usages().isNotEmpty()) {
+            Node usage = binary.usages().first();
+            if (usage instanceof LogicBinaryNode) {
+                processBinary((LogicBinaryNode) usage);
+            } else if (usage instanceof IfNode) {
+                if (binary instanceof LogicConjunctionNode) {
+                    processIf(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (IfNode) usage, false);
+                } else if (binary instanceof LogicDisjunctionNode) {
+                    processIf(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (IfNode) usage, true);
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else if (usage instanceof ConditionalNode) {
+                if (binary instanceof LogicConjunctionNode) {
+                    processConditional(binary.getX(), binary.isXNegated(), binary.getY(), binary.isYNegated(), (ConditionalNode) usage, false);
+                } else if (binary instanceof LogicDisjunctionNode) {
+                    processConditional(binary.getX(), !binary.isXNegated(), binary.getY(), !binary.isYNegated(), (ConditionalNode) usage, true);
+                } else {
+                    throw GraalInternalError.shouldNotReachHere();
+                }
+            } else {
+                throw GraalInternalError.shouldNotReachHere();
+            }
+        }
+        binary.safeDelete();
+    }
+
+    private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, boolean negateTargets) {
+        AbstractBeginNode trueTarget = negateTargets ? ifNode.falseSuccessor() : ifNode.trueSuccessor();
+        AbstractBeginNode falseTarget = negateTargets ? ifNode.trueSuccessor() : ifNode.falseSuccessor();
+        double p = Math.sqrt(ifNode.probability(trueTarget));
+        ifNode.clearSuccessors();
+        Graph graph = ifNode.graph();
+        MergeNode falseTargetMerge = graph.add(new MergeNode());
+        falseTargetMerge.setNext(falseTarget);
+        EndNode firstFalseEnd = graph.add(new EndNode());
+        EndNode secondFalseEnd = graph.add(new EndNode());
+        falseTargetMerge.addForwardEnd(firstFalseEnd);
+        falseTargetMerge.addForwardEnd(secondFalseEnd);
+        AbstractBeginNode firstFalseTarget = AbstractBeginNode.begin(firstFalseEnd);
+        AbstractBeginNode secondFalseTarget = AbstractBeginNode.begin(secondFalseEnd);
+        AbstractBeginNode secondIf = AbstractBeginNode.begin(graph.add(new IfNode(y, yNegated ? firstFalseTarget : trueTarget, yNegated ? trueTarget : firstFalseTarget, yNegated ? 1 - p : p)));
+        IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondFalseTarget : secondIf, xNegated ? secondIf : secondFalseTarget, xNegated ? 1 - p : p));
+        ifNode.replaceAtPredecessor(firstIf);
+        ifNode.safeDelete();
+    }
+
+    private static void processConditional(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, ConditionalNode conditional, boolean negateTargets) {
+        ValueNode trueTarget = negateTargets ? conditional.falseValue() : conditional.trueValue();
+        ValueNode falseTarget = negateTargets ? conditional.trueValue() : conditional.falseValue();
+        Graph graph = conditional.graph();
+        ConditionalNode secondConditional = graph.unique(new ConditionalNode(y, yNegated ? falseTarget : trueTarget, yNegated ? trueTarget : falseTarget));
+        ConditionalNode firstConditional = graph.unique(new ConditionalNode(x, xNegated ? falseTarget : secondConditional, xNegated ? secondConditional : falseTarget));
+        conditional.replaceAndDelete(firstConditional);
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -105,7 +105,7 @@
         }
 
         @Override
-        protected Set<Object> afterSplit(BeginNode node, Set<Object> oldState) {
+        protected Set<Object> afterSplit(AbstractBeginNode node, Set<Object> oldState) {
             return new HashSet<>(oldState);
         }
 
@@ -214,7 +214,7 @@
         }
 
         @Override
-        protected MemoryMap afterSplit(BeginNode node, MemoryMap oldState) {
+        protected MemoryMap afterSplit(AbstractBeginNode node, MemoryMap oldState) {
             MemoryMap result = new MemoryMap(oldState);
             if (node.predecessor() instanceof InvokeWithExceptionNode) {
                 /*
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/GuardLoweringPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -171,11 +171,11 @@
 
         private void lowerToIf(GuardNode guard) {
             StructuredGraph graph = (StructuredGraph) guard.graph();
-            BeginNode fastPath = graph.add(new BeginNode());
+            AbstractBeginNode fastPath = graph.add(new BeginNode());
             DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.action(), guard.reason()));
-            BeginNode deoptBranch = BeginNode.begin(deopt);
-            BeginNode trueSuccessor;
-            BeginNode falseSuccessor;
+            AbstractBeginNode deoptBranch = AbstractBeginNode.begin(deopt);
+            AbstractBeginNode trueSuccessor;
+            AbstractBeginNode falseSuccessor;
             insertLoopExits(deopt);
             if (guard.negated()) {
                 trueSuccessor = deoptBranch;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -532,7 +532,7 @@
             return result;
         }
 
-        private void queueMerge(EndNode end) {
+        private void queueMerge(AbstractEndNode end) {
             MergeNode merge = end.merge();
             if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
                 queuedNodes.mark(merge);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Tue Apr 30 22:22:42 2013 +0200
@@ -495,7 +495,7 @@
             }
 
             // create one separate block for each invoked method
-            BeginNode[] successors = new BeginNode[numberOfMethods + 1];
+            AbstractBeginNode[] successors = new AbstractBeginNode[numberOfMethods + 1];
             for (int i = 0; i < numberOfMethods; i++) {
                 successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
             }
@@ -507,7 +507,7 @@
             } else {
                 unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
             }
-            successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+            successors[successors.length - 1] = AbstractBeginNode.begin(unknownTypeSux);
 
             // replace the invoke exception edge
             if (invoke instanceof InvokeWithExceptionNode) {
@@ -533,7 +533,7 @@
 
             // do the actual inlining for every invoke
             for (int i = 0; i < numberOfMethods; i++) {
-                BeginNode node = successors[i];
+                AbstractBeginNode node = successors[i];
                 Invoke invokeForInlining = (Invoke) node.next();
 
                 ResolvedJavaType commonType;
@@ -616,10 +616,10 @@
         private void inlineSingleMethod(StructuredGraph graph, InliningCallback callback, Replacements replacements, Assumptions assumptions, MetaAccessProvider runtime) {
             assert concretes.size() == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
 
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
+            AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
 
-            BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
-            BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
+            AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+            AbstractBeginNode[] successors = new AbstractBeginNode[]{calleeEntryNode, unknownTypeSux};
             createDispatchOnTypeBeforeInvoke(graph, successors, false, runtime);
 
             calleeEntryNode.setNext(invoke.asNode());
@@ -628,7 +628,7 @@
             inline(invoke, concrete, callback, replacements, assumptions, false);
         }
 
-        private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) {
+        private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, AbstractBeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider runtime) {
             assert ptypes.size() >= 1;
 
             Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
@@ -728,13 +728,13 @@
             return costEstimateMethodDispatch < costEstimateTypeDispatch;
         }
 
-        private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
-                        boolean useForInlining) {
+        private static AbstractBeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge,
+                        PhiNode exceptionObjectPhi, boolean useForInlining) {
             Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
-            BeginNode calleeEntryNode = graph.add(new BeginNode());
+            AbstractBeginNode calleeEntryNode = graph.add(new BeginNode());
             calleeEntryNode.setNext(duplicatedInvoke.asNode());
 
-            EndNode endNode = graph.add(new EndNode());
+            AbstractEndNode endNode = graph.add(new EndNode());
             duplicatedInvoke.setNext(endNode);
             returnMerge.addForwardEnd(endNode);
 
@@ -769,7 +769,7 @@
                 // set new state (pop old exception object, push new one)
                 newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
 
-                EndNode endNode = graph.add(new EndNode());
+                AbstractEndNode endNode = graph.add(new EndNode());
                 newExceptionEdge.setNext(endNode);
                 exceptionMerge.addForwardEnd(endNode);
                 exceptionObjectPhi.addInput(newExceptionEdge);
@@ -812,9 +812,9 @@
         private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider runtime) {
             InliningUtil.receiverNullCheck(invoke);
 
-            BeginNode invocationEntry = graph.add(new BeginNode());
-            BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
-            BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
+            AbstractBeginNode invocationEntry = graph.add(new BeginNode());
+            AbstractBeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+            AbstractBeginNode[] successors = new AbstractBeginNode[]{invocationEntry, unknownTypeSux};
             createDispatchOnTypeBeforeInvoke(graph, successors, true, runtime);
 
             invocationEntry.setNext(invoke.asNode());
@@ -824,8 +824,8 @@
             replaceInvokeCallTarget(invoke, graph, kind, target);
         }
 
-        private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
-            return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
+        private static AbstractBeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
+            return AbstractBeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
         }
 
         @Override
@@ -1175,7 +1175,7 @@
             }
         }
         // ensure proper anchoring of things that were anchored to the StartNode
-        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.asNode()));
+        replacements.put(entryPointNode, AbstractBeginNode.prevBegin(invoke.asNode()));
 
         assert invoke.asNode().successors().first() != null : invoke;
         assert invoke.asNode().predecessor() != null;
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -169,7 +169,7 @@
             fixedCount++;
         }
         if (fixedCount > 1) {
-            if (fixed instanceof EndNode && !(((EndNode) fixed).merge() instanceof LoopBeginNode)) {
+            if (fixed instanceof AbstractEndNode && !(((AbstractEndNode) fixed).merge() instanceof LoopBeginNode)) {
                 metricDuplicationEnd.increment();
                 if (decision.doTransform(merge, fixedCount)) {
                     metricDuplicationEndPerformed.increment();
@@ -246,18 +246,18 @@
                 fixed = ((FixedWithNextNode) fixed).next();
             }
 
-            EndNode endAfter = createNewMerge(fixed, stateAfter);
+            AbstractEndNode endAfter = createNewMerge(fixed, stateAfter);
             MergeNode mergeAfter = endAfter.merge();
             fixedNodes.add(endAfter);
             final HashSet<Node> duplicatedNodes = buildDuplicatedNodeSet(fixedNodes, stateAfter);
             mergeAfter.clearEnds();
             expandDuplicated(duplicatedNodes, mergeAfter);
 
-            List<EndNode> endSnapshot = merge.forwardEnds().snapshot();
+            List<AbstractEndNode> endSnapshot = merge.forwardEnds().snapshot();
             List<PhiNode> phiSnapshot = merge.phis().snapshot();
 
             int endIndex = 0;
-            for (final EndNode forwardEnd : merge.forwardEnds()) {
+            for (final AbstractEndNode forwardEnd : merge.forwardEnds()) {
                 Map<Node, Node> duplicates;
                 if (replacements == null || replacements.get(endIndex) == null) {
                     duplicates = graph.addDuplicates(duplicatedNodes, (DuplicationReplacement) null);
@@ -269,14 +269,14 @@
                 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));
+                mergeAfter.addForwardEnd((AbstractEndNode) duplicates.get(endAfter));
 
                 // re-wire the duplicated ValueAnchorNode to the predecessor of the corresponding
                 // EndNode
                 FixedNode anchorDuplicate = (FixedNode) duplicates.get(anchor);
                 ((FixedWithNextNode) forwardEnd.predecessor()).setNext(anchorDuplicate);
                 // move dependencies on the ValueAnchorNode to the previous BeginNode
-                BeginNode prevBegin = BeginNode.prevBegin(anchorDuplicate);
+                AbstractBeginNode prevBegin = AbstractBeginNode.prevBegin(anchorDuplicate);
                 anchorDuplicate.replaceAtUsages(prevBegin);
 
                 // re-wire the phi duplicates to the correct input
@@ -293,7 +293,7 @@
                 endIndex++;
             }
             GraphUtil.killCFG(merge);
-            for (EndNode forwardEnd : endSnapshot) {
+            for (AbstractEndNode forwardEnd : endSnapshot) {
                 forwardEnd.safeDelete();
             }
             for (PhiNode phi : phiSnapshot) {
@@ -428,9 +428,9 @@
          * @param stateAfterMerge The frame state that should be used for the merge.
          * @return The newly created end node.
          */
-        private EndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
+        private AbstractEndNode createNewMerge(FixedNode successor, FrameState stateAfterMerge) {
             MergeNode newBottomMerge = graph.add(new MergeNode());
-            EndNode newBottomEnd = graph.add(new EndNode());
+            AbstractEndNode newBottomEnd = graph.add(new EndNode());
             newBottomMerge.addForwardEnd(newBottomEnd);
             newBottomMerge.setStateAfter(stateAfterMerge);
             ((FixedWithNextNode) successor.predecessor()).setNext(newBottomEnd);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Tue Apr 30 22:22:42 2013 +0200
@@ -107,6 +107,7 @@
     public static int     LoopMaxUnswitch                    = 3;
     public static int     LoopUnswitchMaxIncrease            = 50;
     public static int     LoopUnswitchUncertaintyBoost       = 5;
+    public static boolean UseLoopLimitChecks                 = true;
 
     // debugging settings
     public static boolean ZapStackOnMethodEntry              = ____;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Tue Apr 30 22:22:42 2013 +0200
@@ -34,7 +34,7 @@
     private static final DebugMetric disabledOptimisticOptsMetric = Debug.metric("DisabledOptimisticOpts");
 
     public static enum Optimization {
-        RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability
+        RemoveNeverExecutedCode, UseTypeCheckedInlining, UseTypeCheckHints, UseExceptionProbabilityForOperations, UseExceptionProbability, UseLoopLimitChecks
     }
 
     private final Set<Optimization> enabledOpts;
@@ -47,6 +47,7 @@
         addOptimization(method, DeoptimizationReason.TypeCheckedInliningViolated, Optimization.UseTypeCheckedInlining);
         addOptimization(method, DeoptimizationReason.OptimizedTypeCheckViolated, Optimization.UseTypeCheckHints);
         addOptimization(method, DeoptimizationReason.NotCompiledExceptionHandler, Optimization.UseExceptionProbability);
+        addOptimization(method, DeoptimizationReason.LoopLimitCheck, Optimization.UseLoopLimitChecks);
     }
 
     private void addOptimization(ResolvedJavaMethod method, DeoptimizationReason deoptReason, Optimization optimization) {
@@ -109,6 +110,10 @@
         return GraalOptions.UseExceptionProbabilityForOperations && enabledOpts.contains(Optimization.UseExceptionProbabilityForOperations);
     }
 
+    public boolean useLoopLimitChecks() {
+        return GraalOptions.UseLoopLimitChecks && enabledOpts.contains(Optimization.UseLoopLimitChecks);
+    }
+
     public boolean lessOptimisticThan(OptimisticOptimizations other) {
         for (Optimization opt : Optimization.values()) {
             if (!enabledOpts.contains(opt) && other.enabledOpts.contains(opt)) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Tue Apr 30 22:22:42 2013 +0200
@@ -70,7 +70,7 @@
             if (scope.start instanceof LoopBeginNode) {
                 assert scope.parent != null;
                 double parentProbability = 0;
-                for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
+                for (AbstractEndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
                     parentProbability += nodeProbabilities.get(end);
                 }
                 return parentProbability / scope.parent.minPathProbability;
@@ -170,7 +170,7 @@
             int pathBeginCount = pathBeginNodes.size();
 
             for (Node sux : controlSplit.successors()) {
-                double probability = controlSplit.probability((BeginNode) sux);
+                double probability = controlSplit.probability((AbstractBeginNode) sux);
                 if (probability > maxProbability) {
                     maxProbability = probability;
                     maxSux = sux;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Tue Apr 30 22:22:42 2013 +0200
@@ -208,7 +208,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
             assert node.predecessor() != null;
             Node pred = node.predecessor();
             if (pred instanceof Invoke) {
@@ -275,7 +275,7 @@
         }
 
         @Override
-        public void afterSplit(BeginNode node) {
+        public void afterSplit(AbstractBeginNode node) {
             // nothing to do...
         }
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/MergeableState.java	Tue Apr 30 22:22:42 2013 +0200
@@ -36,5 +36,5 @@
 
     void loopEnds(LoopBeginNode loopBegin, List<T> loopEndStates);
 
-    void afterSplit(BeginNode node);
+    void afterSplit(AbstractBeginNode node);
 }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/PostOrderNodeIterator.java	Tue Apr 30 22:22:42 2013 +0200
@@ -43,7 +43,7 @@
 public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
 
     private final NodeBitMap visitedEnds;
-    private final Deque<BeginNode> nodeQueue;
+    private final Deque<AbstractBeginNode> nodeQueue;
     private final IdentityHashMap<FixedNode, T> nodeStates;
     private final FixedNode start;
 
@@ -109,13 +109,13 @@
             for (Node node : successors) {
                 if (node != null) {
                     nodeStates.put((FixedNode) node.predecessor(), state);
-                    nodeQueue.addFirst((BeginNode) node);
+                    nodeQueue.addFirst((AbstractBeginNode) node);
                 }
             }
         } else {
             for (Node node : x.successors()) {
                 if (node != null) {
-                    nodeQueue.addFirst((BeginNode) node);
+                    nodeQueue.addFirst((AbstractBeginNode) node);
                 }
             }
         }
@@ -124,7 +124,7 @@
     private FixedNode nextQueuedNode() {
         int maxIterations = nodeQueue.size();
         while (maxIterations-- > 0) {
-            BeginNode node = nodeQueue.removeFirst();
+            AbstractBeginNode node = nodeQueue.removeFirst();
             if (node instanceof MergeNode) {
                 MergeNode merge = (MergeNode) node;
                 state = nodeStates.get(merge.forwardEndAt(0)).clone();
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantBlockIterator.java	Tue Apr 30 22:22:42 2013 +0200
@@ -115,16 +115,16 @@
                             current = successor;
                             continue;
                         } else {
-                            if (current.getEndNode() instanceof EndNode) {
+                            if (current.getEndNode() instanceof AbstractEndNode) {
                                 assert successor.getPredecessors().size() > 1 : "invalid block schedule at " + successor.getBeginNode();
-                                EndNode end = (EndNode) current.getEndNode();
+                                AbstractEndNode end = (AbstractEndNode) current.getEndNode();
 
                                 // add the end node and see if the merge is ready for processing
                                 assert !states.containsKey(end);
                                 states.put(end, state);
                                 MergeNode merge = end.merge();
                                 boolean endsVisited = true;
-                                for (EndNode forwardEnd : merge.forwardEnds()) {
+                                for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
                                     if (!states.containsKey(forwardEnd)) {
                                         endsVisited = false;
                                         break;
@@ -162,7 +162,7 @@
                     MergeNode merge = (MergeNode) current.getBeginNode();
                     ArrayList<StateT> mergedStates = new ArrayList<>(merge.forwardEndCount());
                     for (Block predecessor : current.getPredecessors()) {
-                        EndNode end = (EndNode) predecessor.getEndNode();
+                        AbstractEndNode end = (AbstractEndNode) predecessor.getEndNode();
                         mergedStates.add(states.get(end));
                     }
                     state = closure.merge(current, mergedStates);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java	Tue Apr 30 22:22:42 2013 +0200
@@ -41,7 +41,7 @@
 
         protected abstract StateT merge(MergeNode merge, List<StateT> states);
 
-        protected abstract StateT afterSplit(BeginNode node, StateT oldState);
+        protected abstract StateT afterSplit(AbstractBeginNode node, StateT oldState);
 
         protected abstract Map<LoopExitNode, StateT> processLoop(LoopBeginNode loop, StateT initialState);
     }
@@ -70,7 +70,7 @@
     }
 
     public static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, Set<FixedNode> boundary) {
-        Deque<BeginNode> nodeQueue = new ArrayDeque<>();
+        Deque<AbstractBeginNode> nodeQueue = new ArrayDeque<>();
         IdentityHashMap<FixedNode, StateT> blockEndStates = new IdentityHashMap<>();
 
         StateT state = initialState;
@@ -107,7 +107,7 @@
                             assert !blockEndStates.containsKey(current);
                             blockEndStates.put(current, state);
                             boolean endsVisited = true;
-                            for (EndNode forwardEnd : merge.forwardEnds()) {
+                            for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
                                 if (!blockEndStates.containsKey(forwardEnd)) {
                                     endsVisited = false;
                                     break;
@@ -116,7 +116,7 @@
                             if (endsVisited) {
                                 ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
                                 for (int i = 0; i < merge.forwardEndCount(); i++) {
-                                    EndNode forwardEnd = merge.forwardEndAt(i);
+                                    AbstractEndNode forwardEnd = merge.forwardEndAt(i);
                                     assert blockEndStates.containsKey(forwardEnd);
                                     StateT other = blockEndStates.get(forwardEnd);
                                     states.add(other);
@@ -134,11 +134,11 @@
                         continue;
                     } else {
                         while (successors.hasNext()) {
-                            BeginNode successor = (BeginNode) successors.next();
+                            AbstractBeginNode successor = (AbstractBeginNode) successors.next();
                             blockEndStates.put(successor, closure.afterSplit(successor, state));
                             nodeQueue.add(successor);
                         }
-                        state = closure.afterSplit((BeginNode) firstSuccessor, state);
+                        state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
                         current = firstSuccessor;
                         continue;
                     }
@@ -151,7 +151,7 @@
             } else {
                 current = nodeQueue.removeFirst();
                 state = blockEndStates.get(current);
-                assert !(current instanceof MergeNode) && current instanceof BeginNode;
+                assert !(current instanceof MergeNode) && current instanceof AbstractBeginNode;
             }
         } while (true);
     }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ScopedPostOrderNodeIterator.java	Tue Apr 30 22:22:42 2013 +0200
@@ -141,7 +141,7 @@
         return result;
     }
 
-    private void queueMerge(EndNode end) {
+    private void queueMerge(AbstractEndNode end) {
         MergeNode merge = end.merge();
         if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
             queue(merge);
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/schedule/SchedulePhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -652,7 +652,7 @@
                 }
             }
 
-            if (instruction instanceof BeginNode) {
+            if (instruction instanceof AbstractBeginNode) {
                 ArrayList<ProxyNode> proxies = (instruction instanceof LoopExitNode) ? new ArrayList<ProxyNode>() : null;
                 for (ScheduledNode inBlock : blockToNodesMap.get(b)) {
                     if (!visited.isMarked(inBlock)) {
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/tiers/LowTierContext.java	Tue Apr 30 22:22:42 2013 +0200
@@ -25,17 +25,24 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
 
 public class LowTierContext extends PhaseContext {
 
     private final TargetDescription target;
+    private final OptimisticOptimizations optimisticOpts;
 
-    public LowTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target) {
+    public LowTierContext(MetaAccessProvider runtime, Assumptions assumptions, Replacements replacements, TargetDescription target, OptimisticOptimizations optimisticOpts) {
         super(runtime, assumptions, replacements);
         this.target = target;
+        this.optimisticOpts = optimisticOpts;
     }
 
     public TargetDescription getTarget() {
         return target;
     }
+
+    public OptimisticOptimizations getOptimisticOptimizations() {
+        return optimisticOpts;
+    }
 }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinter.java	Tue Apr 30 22:22:42 2013 +0200
@@ -162,7 +162,7 @@
             PhiNode phi = (PhiNode) node;
             assert nodeBlock.getBeginNode() == phi.merge();
             for (Block pred : nodeBlock.getPredecessors()) {
-                schedule(phi.valueAt((EndNode) pred.getEndNode()), pred);
+                schedule(phi.valueAt((AbstractEndNode) pred.getEndNode()), pred);
             }
 
         } else {
@@ -471,7 +471,7 @@
             return "-";
         }
         String prefix;
-        if (node instanceof BeginNode && lir == null) {
+        if (node instanceof AbstractBeginNode && lir == null) {
             prefix = "B";
         } else if (node instanceof ValueNode) {
             ValueNode value = (ValueNode) node;
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Tue Apr 30 22:22:42 2013 +0200
@@ -165,9 +165,9 @@
                     printProperty(bit, "true");
                 }
             }
-            if (node.getClass() == BeginNode.class) {
+            if (node.getClass() == AbstractBeginNode.class) {
                 printProperty("shortName", "B");
-            } else if (node.getClass() == EndNode.class) {
+            } else if (node.getClass() == AbstractEndNode.class) {
                 printProperty("shortName", "E");
             }
             if (node.predecessor() != null) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetFrameStateCleanupPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -93,7 +93,7 @@
         }
 
         @Override
-        protected CleanupState afterSplit(BeginNode node, CleanupState oldState) {
+        protected CleanupState afterSplit(AbstractBeginNode node, CleanupState oldState) {
             return new CleanupState(oldState.containsFrameState);
         }
 
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -139,8 +139,8 @@
         IdentityHashMap<Node, Node> path = new IdentityHashMap<>();
         flood.add(graph.start());
         for (Node current : flood) {
-            if (current instanceof EndNode) {
-                EndNode end = (EndNode) current;
+            if (current instanceof AbstractEndNode) {
+                AbstractEndNode end = (AbstractEndNode) current;
                 flood.add(end.merge());
                 if (!path.containsKey(end.merge())) {
                     path.put(end.merge(), end);
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Apr 30 20:56:43 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Tue Apr 30 22:22:42 2013 +0200
@@ -272,7 +272,7 @@
         graph.addBeforeFixed(invoke.asNode(), read);
         // The read must not float outside its block otherwise it may float above an explicit zero
         // check on its base address
-        read.dependencies().add(BeginNode.prevBegin(invoke.asNode()));
+        read.dependencies().add(AbstractBeginNode.prevBegin(invoke.asNode()));
         return read;
     }
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Tue Apr 30 20:56:43 2013 +0200
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Tue Apr 30 22:22:42 2013 +0200
@@ -802,6 +802,7 @@
   set_int("deoptReasonJsrMismatch", Deoptimization::Reason_jsr_mismatch);
   set_int("deoptReasonDiv0Check", Deoptimization::Reason_div0_check);
   set_int("deoptReasonConstraint", Deoptimization::Reason_constraint);
+  set_int("deoptReasonLoopLimitCheck", Deoptimization::Reason_loop_limit_check);
 
   set_int("deoptActionNone", Deoptimization::Action_none);
   set_int("deoptActionMaybeRecompile", Deoptimization::Action_maybe_recompile);