changeset 5436:16c27447923c

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Wed, 23 May 2012 11:55:31 +0200
parents 1d63466ba795 (current diff) 142237644367 (diff)
children 451327d8543b
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NullCheckNode.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfCanonicalizerTest.java
diffstat 51 files changed, 1582 insertions(+), 936 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed May 23 11:55:31 2012 +0200
@@ -381,11 +381,11 @@
 
                 if (instr instanceof GuardNode) {
                     GuardNode guardNode = (GuardNode) instr;
-                    if (guardNode.condition() instanceof NullCheckNode) {
-                        NullCheckNode nullCheckNode = (NullCheckNode) guardNode.condition();
-                        if (!nullCheckNode.expectedNull && nextInstr instanceof Access) {
+                    if (guardNode.condition() instanceof IsNullNode && guardNode.negated()) {
+                        IsNullNode isNullNode = (IsNullNode) guardNode.condition();
+                        if (nextInstr instanceof Access) {
                             Access access = (Access) nextInstr;
-                            if (nullCheckNode.object() == access.object() && canBeNullCheck(access.location())) {
+                            if (isNullNode.object() == access.object() && canBeNullCheck(access.location())) {
                                 //TTY.println("implicit null check");
                                 access.setNullCheck(true);
                                 continue;
@@ -404,6 +404,8 @@
             if (instr instanceof ValueNode) {
                 try {
                     doRoot((ValueNode) instr);
+                } catch (GraalInternalError e) {
+                    throw e.addContext(instr);
                 } catch (Throwable e) {
                     throw new GraalInternalError(e).addContext(instr);
                 }
@@ -667,25 +669,29 @@
     }
 
     @Override
-    public void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
-        if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) {
-            emitNullCheckGuard((NullCheckNode) comp, leafGraphId);
-        } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) {
+    public void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) {
+        if (comp instanceof IsNullNode && negated) {
+            emitNullCheckGuard(((IsNullNode) comp).object(), leafGraphId);
+        } else if (comp instanceof ConstantNode && (comp.asConstant().asBoolean() != negated)) {
             // True constant, nothing to emit.
             // False constants are handled within emitBranch.
         } else {
             // Fall back to a normal branch.
             LIRDebugInfo info = state(leafGraphId);
             LabelRef stubEntry = createDeoptStub(action, deoptReason, info, comp);
-            emitBranch(comp, null, stubEntry, info);
+            if (negated) {
+                emitBranch(comp, stubEntry, null, info);
+            } else {
+                emitBranch(comp, null, stubEntry, info);
+            }
         }
     }
 
-    protected abstract void emitNullCheckGuard(NullCheckNode node, long leafGraphId);
+    protected abstract void emitNullCheckGuard(ValueNode object, long leafGraphId);
 
     public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
-        if (node instanceof NullCheckNode) {
-            emitNullCheckBranch((NullCheckNode) node, trueSuccessor, falseSuccessor, info);
+        if (node instanceof IsNullNode) {
+            emitNullCheckBranch((IsNullNode) node, trueSuccessor, falseSuccessor, info);
         } else if (node instanceof CompareNode) {
             emitCompareBranch((CompareNode) node, trueSuccessor, falseSuccessor, info);
         } else if (node instanceof InstanceOfNode) {
@@ -699,9 +705,8 @@
         }
     }
 
-    private void emitNullCheckBranch(NullCheckNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
-        Condition cond = node.expectedNull ? Condition.NE : Condition.EQ;
-        emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, cond, false, falseSuccessor, info);
+    private void emitNullCheckBranch(IsNullNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+        emitBranch(operand(node.object()), CiConstant.NULL_OBJECT, Condition.NE, false, falseSuccessor, info);
         if (trueSuccessor != null) {
             emitJump(trueSuccessor, null);
         }
@@ -717,7 +722,7 @@
     private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
         XirArgument obj = toXirArgument(x.object());
         XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile());
-        emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor);
+        emitXir(snippet, x, info, null, false, trueSuccessor, falseSuccessor);
     }
 
     public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) {
@@ -745,8 +750,8 @@
     }
 
     public Variable emitConditional(BooleanNode node, CiValue trueValue, CiValue falseValue) {
-        if (node instanceof NullCheckNode) {
-            return emitNullCheckConditional((NullCheckNode) node, trueValue, falseValue);
+        if (node instanceof IsNullNode) {
+            return emitNullCheckConditional((IsNullNode) node, trueValue, falseValue);
         } else if (node instanceof CompareNode) {
             return emitCompareConditional((CompareNode) node, trueValue, falseValue);
         } else if (node instanceof InstanceOfNode) {
@@ -758,15 +763,14 @@
         }
     }
 
-    private Variable emitNullCheckConditional(NullCheckNode node, CiValue trueValue, CiValue falseValue) {
-        Condition cond = node.expectedNull ? Condition.EQ : Condition.NE;
-        return emitCMove(operand(node.object()), CiConstant.NULL_OBJECT, cond, false, trueValue, falseValue);
+    private Variable emitNullCheckConditional(IsNullNode node, CiValue trueValue, CiValue falseValue) {
+        return emitCMove(operand(node.object()), CiConstant.NULL_OBJECT, Condition.EQ, false, trueValue, falseValue);
     }
 
     private Variable emitInstanceOfConditional(InstanceOfNode x, CiValue trueValue, CiValue falseValue) {
         XirArgument obj = toXirArgument(x.object());
-        XirArgument trueArg = toXirArgument(x.negated() ? falseValue : trueValue);
-        XirArgument falseArg = toXirArgument(x.negated() ? trueValue : falseValue);
+        XirArgument trueArg = toXirArgument(trueValue);
+        XirArgument falseArg = toXirArgument(falseValue);
         XirSnippet snippet = xir.genMaterializeInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), x.profile());
         return (Variable) emitXir(snippet, null, null, false);
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java	Wed May 23 11:55:31 2012 +0200
@@ -44,6 +44,7 @@
     private static final DebugMetric metricInstanceOfRemoved = Debug.metric("InstanceOfRemoved");
     private static final DebugMetric metricNullCheckRemoved = Debug.metric("NullCheckRemoved");
     private static final DebugMetric metricNullCheckGuardRemoved = Debug.metric("NullCheckGuardRemoved");
+    private static final DebugMetric metricGuardsReplaced = Debug.metric("GuardsReplaced");
 
     private StructuredGraph graph;
 
@@ -58,17 +59,23 @@
         private IdentityHashMap<ValueNode, RiResolvedType> knownTypes;
         private HashSet<ValueNode> knownNotNull;
         private HashSet<ValueNode> knownNull;
+        private IdentityHashMap<BooleanNode, ValueNode> trueConditions;
+        private IdentityHashMap<BooleanNode, ValueNode> falseConditions;
 
         public State() {
             this.knownTypes = new IdentityHashMap<>();
             this.knownNotNull = new HashSet<>();
             this.knownNull = new HashSet<>();
+            this.trueConditions = new IdentityHashMap<>();
+            this.falseConditions = new IdentityHashMap<>();
         }
 
-        public State(IdentityHashMap<ValueNode, RiResolvedType> knownTypes, HashSet<ValueNode> knownNotNull, HashSet<ValueNode> knownNull) {
-            this.knownTypes = new IdentityHashMap<>(knownTypes);
-            this.knownNotNull = new HashSet<>(knownNotNull);
-            this.knownNull = new HashSet<>(knownNull);
+        public State(State other) {
+            this.knownTypes = new IdentityHashMap<>(other.knownTypes);
+            this.knownNotNull = new HashSet<>(other.knownNotNull);
+            this.knownNull = new HashSet<>(other.knownNull);
+            this.trueConditions = new IdentityHashMap<>(other.trueConditions);
+            this.falseConditions = new IdentityHashMap<>(other.falseConditions);
         }
 
         @Override
@@ -76,6 +83,8 @@
             IdentityHashMap<ValueNode, RiResolvedType> newKnownTypes = new IdentityHashMap<>();
             HashSet<ValueNode> newKnownNotNull = new HashSet<>();
             HashSet<ValueNode> newKnownNull = new HashSet<>();
+            IdentityHashMap<BooleanNode, ValueNode> newTrueConditions = new IdentityHashMap<>();
+            IdentityHashMap<BooleanNode, ValueNode> newFalseConditions = new IdentityHashMap<>();
 
             for (Map.Entry<ValueNode, RiResolvedType> entry : knownTypes.entrySet()) {
                 ValueNode node = entry.getKey();
@@ -116,6 +125,43 @@
                     newKnownNull.add(node);
                 }
             }
+            for (Map.Entry<BooleanNode, ValueNode> entry : trueConditions.entrySet()) {
+                BooleanNode check = entry.getKey();
+                ValueNode guard = entry.getValue();
+
+                for (State other : withStates) {
+                    ValueNode otherGuard = other.trueConditions.get(check);
+                    if (otherGuard == null) {
+                        guard = null;
+                        break;
+                    }
+                    if (otherGuard != guard) {
+                        guard = merge;
+                    }
+                }
+                if (guard != null) {
+                    newTrueConditions.put(check, guard);
+                }
+            }
+            for (Map.Entry<BooleanNode, ValueNode> entry : falseConditions.entrySet()) {
+                BooleanNode check = entry.getKey();
+                ValueNode guard = entry.getValue();
+
+                for (State other : withStates) {
+                    ValueNode otherGuard = other.falseConditions.get(check);
+                    if (otherGuard == null) {
+                        guard = null;
+                        break;
+                    }
+                    if (otherGuard != guard) {
+                        guard = merge;
+                    }
+                }
+                if (guard != null) {
+                    newFalseConditions.put(check, guard);
+                }
+            }
+
             /*
             // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values)
             if (!(merge instanceof LoopBeginNode)) {
@@ -150,6 +196,8 @@
             this.knownTypes = newKnownTypes;
             this.knownNotNull = newKnownNotNull;
             this.knownNull = newKnownNull;
+            this.trueConditions = newTrueConditions;
+            this.falseConditions = newFalseConditions;
             return true;
         }
 
@@ -172,7 +220,7 @@
 
         @Override
         public State clone() {
-            return new State(knownTypes, knownNotNull, knownNull);
+            return new State(this);
         }
     }
 
@@ -217,21 +265,29 @@
                 Node pred = node.predecessor();
                 if (pred != null && pred instanceof IfNode) {
                     IfNode ifNode = (IfNode) pred;
+                    if (!(ifNode.compare() instanceof ConstantNode)) {
+                        boolean isTrue = (node == ifNode.trueSuccessor());
+                        if (isTrue) {
+                            state.trueConditions.put(ifNode.compare(), begin);
+                        } else {
+                            state.falseConditions.put(ifNode.compare(), begin);
+                        }
+                    }
                     if (ifNode.compare() instanceof InstanceOfNode) {
                         InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare();
-                        if ((node == ifNode.trueSuccessor()) != instanceOf.negated()) {
+                        if ((node == ifNode.trueSuccessor())) {
                             ValueNode object = instanceOf.object();
                             state.knownNotNull.add(object);
                             state.knownTypes.put(object, tighten(instanceOf.targetClass(), state.getNodeType(object)));
                             metricInstanceOfRegistered.increment();
                         }
-                    } else if (ifNode.compare() instanceof NullCheckNode) {
-                        NullCheckNode nullCheck = (NullCheckNode) ifNode.compare();
-                        boolean isNotNull = (node == ifNode.trueSuccessor()) != nullCheck.expectedNull;
-                        if (isNotNull) {
+                    } else if (ifNode.compare() instanceof IsNullNode) {
+                        IsNullNode nullCheck = (IsNullNode) ifNode.compare();
+                        boolean isNull = (node == ifNode.trueSuccessor());
+                        if (isNull) {
+                            state.knownNull.add(nullCheck.object());
+                        } else {
                             state.knownNotNull.add(nullCheck.object());
-                        } else {
-                            state.knownNull.add(nullCheck.object());
                         }
                         metricNullCheckRegistered.increment();
                     } else if (ifNode.compare() instanceof IsTypeNode) {
@@ -246,22 +302,36 @@
                     }
                 }
                 for (GuardNode guard : begin.guards().snapshot()) {
-                    boolean removeCheck = false;
-                    if (guard.condition() instanceof NullCheckNode) {
-                        NullCheckNode nullCheck = (NullCheckNode) guard.condition();
-                        if (state.knownNotNull.contains(nullCheck.object()) && !nullCheck.expectedNull) {
-                            removeCheck = true;
-                        } else if (state.knownNull.contains(nullCheck.object()) && nullCheck.expectedNull) {
-                            removeCheck = true;
+                    BooleanNode condition = guard.condition();
+                    ValueNode existingGuards = guard.negated() ? state.falseConditions.get(condition) : state.trueConditions.get(condition);
+                    if (existingGuards != null) {
+                        guard.replaceAtUsages(existingGuards);
+                        GraphUtil.killWithUnusedFloatingInputs(guard);
+                        metricGuardsReplaced.increment();
+                    } else {
+                        boolean removeCheck = false;
+                        if (condition instanceof IsNullNode) {
+                            IsNullNode isNull = (IsNullNode) condition;
+                            if (guard.negated() && state.knownNotNull.contains(isNull.object())) {
+                                removeCheck = true;
+                            } else if (!guard.negated() && state.knownNull.contains(isNull.object())) {
+                                removeCheck = true;
+                            }
+                            if (removeCheck) {
+                                metricNullCheckGuardRemoved.increment();
+                            }
                         }
                         if (removeCheck) {
-                            metricNullCheckGuardRemoved.increment();
+                            guard.replaceAtUsages(begin);
+                            GraphUtil.killWithUnusedFloatingInputs(guard);
+                        } else {
+                            if (guard.negated()) {
+                                state.falseConditions.put(condition, guard);
+                            } else {
+                                state.trueConditions.put(condition, guard);
+                            }
                         }
                     }
-                    if (removeCheck) {
-                        guard.replaceAtUsages(begin);
-                        GraphUtil.killWithUnusedFloatingInputs(guard);
-                    }
                 }
             } else if (node instanceof CheckCastNode) {
                 CheckCastNode checkCast = (CheckCastNode) node;
@@ -281,30 +351,37 @@
                 IfNode ifNode = (IfNode) node;
                 BooleanNode replaceWith = null;
                 BooleanNode compare = ifNode.compare();
-                if (compare instanceof InstanceOfNode) {
-                    InstanceOfNode instanceOf = (InstanceOfNode) compare;
-                    ValueNode object = instanceOf.object();
-                    if (state.knownNull.contains(object)) {
-                        replaceWith = ConstantNode.forBoolean(instanceOf.negated(), graph);
-                    } else if (state.knownNotNull.contains(object)) {
-                        RiResolvedType type = state.getNodeType(object);
-                        if (type != null && type.isSubtypeOf(instanceOf.targetClass())) {
-                            replaceWith = ConstantNode.forBoolean(!instanceOf.negated(), graph);
+
+                if (state.trueConditions.containsKey(compare)) {
+                    replaceWith = ConstantNode.forBoolean(true, graph);
+                } else if (state.falseConditions.containsKey(compare)) {
+                    replaceWith = ConstantNode.forBoolean(false, graph);
+                } else {
+                    if (compare instanceof InstanceOfNode) {
+                        InstanceOfNode instanceOf = (InstanceOfNode) compare;
+                        ValueNode object = instanceOf.object();
+                        if (state.knownNull.contains(object)) {
+                            replaceWith = ConstantNode.forBoolean(false, graph);
+                        } else if (state.knownNotNull.contains(object)) {
+                            RiResolvedType type = state.getNodeType(object);
+                            if (type != null && type.isSubtypeOf(instanceOf.targetClass())) {
+                                replaceWith = ConstantNode.forBoolean(true, graph);
+                            }
                         }
-                    }
-                    if (replaceWith != null) {
-                        metricInstanceOfRemoved.increment();
-                    }
-                } else if (compare instanceof NullCheckNode) {
-                    NullCheckNode nullCheck = (NullCheckNode) compare;
-                    ValueNode object = nullCheck.object();
-                    if (state.knownNull.contains(object)) {
-                        replaceWith = ConstantNode.forBoolean(nullCheck.expectedNull, graph);
-                    } else if (state.knownNotNull.contains(object)) {
-                        replaceWith = ConstantNode.forBoolean(!nullCheck.expectedNull, graph);
-                    }
-                    if (replaceWith != null) {
-                        metricNullCheckRemoved.increment();
+                        if (replaceWith != null) {
+                            metricInstanceOfRemoved.increment();
+                        }
+                    } else if (compare instanceof IsNullNode) {
+                        IsNullNode isNull = (IsNullNode) compare;
+                        ValueNode object = isNull.object();
+                        if (state.knownNull.contains(object)) {
+                            replaceWith = ConstantNode.forBoolean(true, graph);
+                        } else if (state.knownNotNull.contains(object)) {
+                            replaceWith = ConstantNode.forBoolean(false, graph);
+                        }
+                        if (replaceWith != null) {
+                            metricNullCheckRemoved.increment();
+                        }
                     }
                 }
                 if (replaceWith != null) {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ConvertDeoptimizeToGuardPhase.java	Wed May 23 11:55:31 2012 +0200
@@ -78,13 +78,14 @@
             IfNode ifNode = (IfNode) deoptBegin.predecessor();
             BeginNode otherBegin = ifNode.trueSuccessor();
             BooleanNode conditionNode = ifNode.compare();
+            boolean negated = false;
             if (deoptBegin == ifNode.trueSuccessor()) {
-                conditionNode = conditionNode.negate();
+                negated = true;
                 otherBegin = ifNode.falseSuccessor();
             }
             BeginNode ifBlockBegin = findBeginNode(ifNode);
             Debug.log("Converting %s on %-5s branch of %s to guard for remaining branch %s. IfBegin=%s", deopt, deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, otherBegin, ifBlockBegin);
-            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), deopt.leafGraphId()));
+            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.reason(), deopt.action(), negated, deopt.leafGraphId()));
             otherBegin.replaceAtUsages(ifBlockBegin);
             FixedNode next = otherBegin.next();
             otherBegin.setNext(null);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Wed May 23 11:55:31 2012 +0200
@@ -284,8 +284,8 @@
             if (usage instanceof FixedNode) {
                 record.localWeight += ((FixedNode) usage).probability();
             }
-            if (usage instanceof NullCheckNode) {
-                assert ((NullCheckNode) usage).object() == node;
+            if (usage instanceof IsNullNode) {
+                assert ((IsNullNode) usage).object() == node;
                 return null;
             } else if (usage instanceof IsTypeNode) {
                 assert ((IsTypeNode) usage).objectClass() == node;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Wed May 23 11:55:31 2012 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.max.cri.ci.*;
@@ -38,6 +39,40 @@
  */
 public class LoweringPhase extends Phase {
 
+    private class LoweringToolBase implements CiLoweringTool {
+
+        @Override
+        public GraalRuntime getRuntime() {
+            return runtime;
+        }
+
+        @Override
+        public Node getGuardAnchor() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Node createNullCheckGuard(ValueNode object, long leafGraphId) {
+            return createGuard(object.graph().unique(new IsNullNode(object)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, true, leafGraphId);
+        }
+
+        @Override
+        public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
+            return createGuard(condition, deoptReason, action, false, leafGraphId);
+        }
+
+        @Override
+        public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) {
+            // TODO (thomaswue): Document why this must not be called on floating nodes.
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CiAssumptions assumptions() {
+            return assumptions;
+        }
+    }
+
     private final GraalRuntime runtime;
     private final CiAssumptions assumptions;
 
@@ -45,6 +80,7 @@
         this.runtime = runtime;
         this.assumptions = assumptions;
     }
+
     @Override
     protected void run(final StructuredGraph graph) {
         // Step 1: repeatedly lower fixed nodes until no new ones are created
@@ -66,29 +102,7 @@
 
         // Step 2: lower the floating nodes
         processed.negate();
-        final CiLoweringTool loweringTool = new CiLoweringTool() {
-
-            @Override
-            public Node getGuardAnchor() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public GraalRuntime getRuntime() {
-                return runtime;
-            }
-
-            @Override
-            public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
-                // TODO (thomaswue): Document why this must not be called on floating nodes.
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public CiAssumptions assumptions() {
-                return assumptions;
-            }
-        };
+        final CiLoweringTool loweringTool = new LoweringToolBase();
         for (Node node : processed) {
             if (node instanceof Lowerable) {
                 assert !(node instanceof FixedNode) || node.predecessor() == null : node;
@@ -105,29 +119,7 @@
         processBlock(cfg.getStartBlock(), activeGuards, processed, null);
 
         processed.negate();
-        final CiLoweringTool loweringTool = new CiLoweringTool() {
-
-            @Override
-            public Node getGuardAnchor() {
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public GraalRuntime getRuntime() {
-                return runtime;
-            }
-
-            @Override
-            public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
-                // TODO (thomaswue): Document why this must not be called on floating nodes.
-                throw new UnsupportedOperationException();
-            }
-
-            @Override
-            public CiAssumptions assumptions() {
-                return assumptions;
-            }
-        };
+        final CiLoweringTool loweringTool = new LoweringToolBase();
         for (Node node : processed) {
             if (node instanceof CheckCastNode) {
                 // This is a checkcast that was created while lowering some other node (e.g. StoreIndexed).
@@ -172,7 +164,7 @@
 
     private void process(final Block b, final NodeBitMap activeGuards, NodeBitMap processed, final Node anchor) {
 
-        final CiLoweringTool loweringTool = new CiLoweringTool() {
+        final CiLoweringTool loweringTool = new LoweringToolBase() {
 
             @Override
             public Node getGuardAnchor() {
@@ -180,12 +172,7 @@
             }
 
             @Override
-            public GraalRuntime getRuntime() {
-                return runtime;
-            }
-
-            @Override
-            public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
+            public Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) {
                 FixedNode guardAnchor = (FixedNode) getGuardAnchor();
                 if (GraalOptions.OptEliminateGuards) {
                     for (Node usage : condition.usages()) {
@@ -194,18 +181,13 @@
                         }
                     }
                 }
-                GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor, deoptReason, action, leafGraphId));
+                GuardNode newGuard = guardAnchor.graph().unique(new GuardNode((BooleanNode) condition, guardAnchor, deoptReason, action, negated, leafGraphId));
                 if (GraalOptions.OptEliminateGuards) {
                     activeGuards.grow();
                     activeGuards.mark(newGuard);
                 }
                 return newGuard;
             }
-
-            @Override
-            public CiAssumptions assumptions() {
-                return assumptions;
-            }
         };
 
         // Lower the instructions of this block.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed May 23 11:55:31 2012 +0200
@@ -578,8 +578,8 @@
     }
 
     @Override
-    protected void emitNullCheckGuard(NullCheckNode node, long leafGraphId) {
-        Variable value = load(operand(node.object()));
+    protected void emitNullCheckGuard(ValueNode object, long leafGraphId) {
+        Variable value = load(operand(object));
         LIRDebugInfo info = state(leafGraphId);
         append(new NullCheckOp(value, info));
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Wed May 23 11:55:31 2012 +0200
@@ -99,15 +99,13 @@
             }
         }
         for (FixedGuardNode guard : graph.getNodes(FixedGuardNode.class)) {
-            for (int i = 0; i < guard.conditions().size(); i++) {
-                BooleanNode condition = guard.conditions().get(i);
-                if (condition != null && condition.usages().size() > 1) {
-                    BooleanNode clone = (BooleanNode) condition.copyWithInputs();
-                    if (DUMP) {
-                        out.println("replaced!! " + clone);
-                    }
-                    guard.conditions().set(i, clone);
+            BooleanNode condition = guard.condition();
+            if (condition != null && condition.usages().size() > 1) {
+                BooleanNode clone = (BooleanNode) condition.copyWithInputs();
+                if (DUMP) {
+                    out.println("replaced!! " + clone);
                 }
+                guard.setCondition(clone);
             }
         }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Wed May 23 11:55:31 2012 +0200
@@ -27,14 +27,10 @@
 import java.util.concurrent.*;
 
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.loop.*;
 import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.*;
-import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
@@ -907,167 +903,13 @@
         }
     }
 
-    /**
-     * Performs replacement of a node with a snippet graph.
-     * @param replacee the node that will be replaced
-     * @param anchor the control flow replacee
-     * @param snippetGraph the graph that the replacee will be replaced with
-     * @param explodeLoops specifies if all the loops in the snippet graph are counted loops that must be completely unrolled
-     * @param args
-     */
-    public static void inlineSnippet(final RiRuntime runtime,
-                    final Node replacee,
-                    final FixedWithNextNode anchor,
-                    final StructuredGraph snippetGraph,
-                    final boolean explodeLoops,
-                    final IsImmutablePredicate immutabilityPredicate,
-                    final Object... args) {
-        Debug.scope("InliningSnippet", snippetGraph.method(), new Runnable() {
-            @Override
-            public void run() {
-                inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, args);
-            }
-        });
-    }
-    private static void inlineSnippet0(RiRuntime runtime,
-                    Node replacee,
-                    FixedWithNextNode anchor,
-                    StructuredGraph snippetGraph,
-                    boolean explodeLoops,
-                    IsImmutablePredicate immutabilityPredicate,
-                    Object... args) {
-
-        Debug.dump(replacee.graph(), "Before lowering %s", replacee);
-
-        // Copy snippet graph, replacing parameters with given args in the process
-        StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
-        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
-        replacements.put(snippetGraph.start(), snippetCopy.start());
-        int localCount = 0;
-        for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) {
-            int index = local.index();
-            if (args[index] instanceof CiConstant) {
-                CiConstant arg = (CiConstant) args[index];
-                assert arg.kind.stackKind() == local.kind() : arg.kind + " != " + local.kind();
-                ConstantNode argNode = ConstantNode.forCiConstant(arg, runtime, snippetCopy);
-                replacements.put(local, argNode);
-                args[index] = null;
-            } else {
-                assert args[index] instanceof ValueNode;
-            }
-            localCount++;
-        }
-        assert localCount == args.length : "snippet argument count mismatch";
-        snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements);
-        if (!replacements.isEmpty()) {
-            new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy);
-        }
-
-        // Explode all loops in the snippet if requested
-        if (explodeLoops && snippetCopy.hasLoops()) {
-            ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false);
-            for (Loop loop : cfg.getLoops()) {
-                LoopBeginNode loopBegin = loop.loopBegin();
-                SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
-                Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
-                int peel = 0;
-                while (!loopBegin.isDeleted()) {
-                    int mark = snippetCopy.getMark();
-                    LoopTransformUtil.peel(loop, wholeLoop);
-                    Debug.dump(snippetCopy, "After peel %d", peel);
-                    new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy);
-                    peel++;
-                }
-                Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
-            }
-            new DeadCodeEliminationPhase().apply(snippetCopy);
-        }
-
-        // Gather the nodes in the snippet that are to be inlined
-        ArrayList<Node> nodes = new ArrayList<>();
-        ReturnNode returnNode = null;
-        StartNode entryPointNode = snippetCopy.start();
-        FixedNode firstCFGNode = entryPointNode.next();
-        replacements.clear();
-        for (Node node : snippetCopy.getNodes()) {
-            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
-                // Do nothing.
-            } else if (node instanceof LocalNode) {
-                LocalNode local = (LocalNode) node;
-                int index = local.index();
-                assert args[index] instanceof ValueNode;
-                ValueNode arg = (ValueNode) args[index];
-                assert arg.kind() == local.kind();
-                replacements.put(node, arg);
-                args[index] = null;
-            } else {
-                nodes.add(node);
-                if (node instanceof ReturnNode) {
-                    returnNode = (ReturnNode) node;
-                }
-            }
-        }
-
-        // Inline the gathered snippet nodes
-        StructuredGraph graph = (StructuredGraph) replacee.graph();
-        int mark = graph.getMark();
-        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
-        Debug.dump(graph, "After inlining snippet %s", snippetCopy.method());
-
-        // Remove all frame states from the inlined snippet graph. Snippets must be atomic (i.e. free
-        // of side-effects that prevent deoptimizing to a point before the snippet).
-        for (Node node : graph.getNewNodes(mark)) {
-            if (node instanceof StateSplit) {
-                StateSplit stateSplit = (StateSplit) node;
-                FrameState frameState = stateSplit.stateAfter();
-                assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + frameState.toString(Verbosity.Debugger);
-                if (frameState != null) {
-                    stateSplit.setStateAfter(null);
-                }
-            }
-        }
-
-        Debug.dump(graph, "After removing frame states");
-
-        // Rewire the control flow graph around the replacee
-        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
-        anchor.replaceAtPredecessors(firstCFGNodeDuplicate);
-        FixedNode next = anchor.next();
-        anchor.setNext(null);
-
-        // Replace all usages of the replacee with the value returned by the snippet
-        Node returnValue = null;
-        if (returnNode != null) {
-            if (returnNode.result() instanceof LocalNode) {
-                returnValue = replacements.get(returnNode.result());
-            } else {
-                returnValue = duplicates.get(returnNode.result());
-            }
-            assert returnValue != null || replacee.usages().isEmpty();
-            replacee.replaceAtUsages(returnValue);
-
-            Node returnDuplicate = duplicates.get(returnNode);
-            returnDuplicate.clearInputs();
-            returnDuplicate.replaceAndDelete(next);
-        }
-
-        // Remove the replacee from its graph
-        replacee.clearInputs();
-        replacee.replaceAtUsages(null);
-        if (replacee instanceof FixedNode) {
-            GraphUtil.killCFG((FixedNode) replacee);
-        } else {
-            replacee.safeDelete();
-        }
-    }
-
     public static void receiverNullCheck(Invoke invoke) {
         MethodCallTargetNode callTarget = invoke.callTarget();
         StructuredGraph graph = (StructuredGraph) invoke.graph();
         NodeInputList<ValueNode> parameters = callTarget.arguments();
         ValueNode firstParam = parameters.size() <= 0 ? null : parameters.get(0);
         if (!callTarget.isStatic() && firstParam.kind() == CiKind.Object && !firstParam.stamp().nonNull()) {
-            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new NullCheckNode(firstParam, false)), RiDeoptReason.ClassCastException, RiDeoptAction.InvalidateReprofile, invoke.leafGraphId())));
+            graph.addBeforeFixed(invoke.node(), graph.add(new FixedGuardNode(graph.unique(new IsNullNode(firstParam)), RiDeoptReason.ClassCastException, RiDeoptAction.InvalidateReprofile, true, invoke.leafGraphId())));
         }
     }
 }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed May 23 11:55:31 2012 +0200
@@ -509,7 +509,11 @@
      * @param replacements the replacement map (can be null if no replacement is to be performed)
      * @return a map which associates the original nodes from {@code nodes} to their duplicates
      */
+    @SuppressWarnings("all")
     public Map<Node, Node> addDuplicates(Iterable<Node> newNodes, Map<Node, Node> replacements) {
+        if (replacements == null) {
+            replacements = Collections.emptyMap();
+        }
         return NodeClass.addGraphDuplicate(this, newNodes, replacements);
     }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java	Wed May 23 11:55:31 2012 +0200
@@ -40,7 +40,7 @@
      */
     public final Class javaMirror;
 
-    HotSpotKlassOop(Compiler compiler, Class javaMirror) {
+    public HotSpotKlassOop(Compiler compiler, Class javaMirror) {
         super(compiler);
         this.javaMirror = javaMirror;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Wed May 23 11:55:31 2012 +0200
@@ -28,10 +28,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.compiler.util.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
@@ -65,7 +63,7 @@
     final HotSpotRegisterConfig regConfig;
     private final HotSpotRegisterConfig globalStubRegConfig;
     private final Compiler compiler;
-    private RiResolvedMethod checkcastSnippet;
+    private CheckCastSnippets.Templates checkcasts;
 
     public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) {
         this.config = config;
@@ -81,15 +79,7 @@
         Snippets.install(this, compiler.getTarget(), new UnsafeSnippets());
         Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets());
         Snippets.install(this, compiler.getTarget(), new CheckCastSnippets());
-        try {
-            if (GraalOptions.CheckcastCounters) {
-                checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastWithCounters", Object.class, Object.class, Object[].class, boolean.class, Counter.class));
-            } else {
-                checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class));
-            }
-        } catch (NoSuchMethodException e) {
-            throw new GraalInternalError(e);
-        }
+        checkcasts = new CheckCastSnippets.Templates(this);
     }
 
 
@@ -294,7 +284,7 @@
             int displacement = ((HotSpotField) field.field()).offset();
             assert field.kind() != CiKind.Illegal;
             ReadNode memoryRead = graph.add(new ReadNode(field.object(), LocationNode.create(field.field(), field.field().kind(true), displacement, graph), field.stamp()));
-            memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, field.leafGraphId()));
+            memoryRead.dependencies().add(tool.createNullCheckGuard(field.object(), field.leafGraphId()));
             graph.replaceFixedWithFixed(field, memoryRead);
             if (field.isVolatile()) {
                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
@@ -306,7 +296,7 @@
             StoreFieldNode storeField = (StoreFieldNode) n;
             HotSpotField field = (HotSpotField) storeField.field();
             WriteNode memoryWrite = graph.add(new WriteNode(storeField.object(), storeField.value(), LocationNode.create(storeField.field(), storeField.field().kind(true), field.offset(), graph)));
-            memoryWrite.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, storeField.leafGraphId()));
+            memoryWrite.dependencies().add(tool.createNullCheckGuard(storeField.object(), storeField.leafGraphId()));
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
 
@@ -370,7 +360,7 @@
                         assert elementType.name().equals("Ljava/lang/Object;") : elementType.name();
                     }
                 } else {
-                    Node guard = tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID);
+                    Node guard = tool.createNullCheckGuard(array, StructuredGraph.INVALID_GRAPH_ID);
                     FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), null, StampFactory.objectNonNull()));
                     arrayClass.dependencies().add(guard);
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), null, StampFactory.objectNonNull()));
@@ -394,7 +384,7 @@
             IndexedLocationNode location = IndexedLocationNode.create(LocationNode.ANY_LOCATION, load.loadKind(), load.displacement(), load.offset(), graph);
             location.setIndexScalingEnabled(false);
             ReadNode memoryRead = graph.add(new ReadNode(load.object(), location, load.stamp()));
-            memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
+            memoryRead.dependencies().add(tool.createNullCheckGuard(load.object(), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -411,35 +401,34 @@
             ReadHubNode objectClassNode = (ReadHubNode) n;
             LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph);
             ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull()));
-            memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
+            memoryRead.dependencies().add(tool.createNullCheckGuard(objectClassNode.object(), StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
             if (shouldLowerCheckcast(graph)) {
-                final Map<CiConstant, CiConstant> hintHubsSet = new IdentityHashMap<>();
-                IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() {
-                    public boolean apply(CiConstant constant) {
-                        return hintHubsSet.containsKey(constant);
-                    }
-                };
                 CheckCastNode checkcast = (CheckCastNode) n;
                 ValueNode hub = checkcast.targetClassInstruction();
                 ValueNode object = checkcast.object();
                 TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
-                StructuredGraph snippetGraph = (StructuredGraph) checkcastSnippet.compilerStorage().get(Graph.class);
-                assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed";
                 HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
                 for (int i = 0; i < hintHubs.length; i++) {
                     hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop();
                 }
-                final CiConstant hintHubsConst = CiConstant.forObject(hintHubs);
-                hintHubsSet.put(hintHubsConst, hintHubsConst);
                 Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact);
+
+                final Counter noHintsCounter;
                 if (GraalOptions.CheckcastCounters) {
-                    Counter noHintsCounter = checkcast.targetClass() == null ? Counter.noHints_unknown : checkcast.targetClass().isInterface() ? Counter.noHints_iface : Counter.noHints_class;
-                    InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact), CiConstant.forObject(noHintsCounter));
+                    if (checkcast.targetClass() == null) {
+                        noHintsCounter = Counter.noHints_unknown;
+                    } else if (checkcast.targetClass().isInterface()) {
+                        noHintsCounter = Counter.noHints_iface;
+                    } else {
+                        noHintsCounter = Counter.noHints_class;
+                    }
                 } else {
-                    InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
+                    noHintsCounter = null;
                 }
+                boolean checkNull = !object.stamp().nonNull();
+                checkcasts.get(hintHubs.length, hints.exact, checkNull, noHintsCounter).instantiate(this, checkcast, checkcast, hub, object, hintHubs, noHintsCounter);
                 new DeadCodeEliminationPhase().apply(graph);
             }
         } else {
@@ -470,7 +459,7 @@
     private static Node createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) n.graph();
         ArrayLengthNode arrayLength = graph.add(new ArrayLengthNode(n.array()));
-        Node guard = tool.createGuard(graph.unique(new CompareNode(n.index(), Condition.BT, arrayLength)), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, n.leafGraphId());
+        Node guard = tool.createGuard(graph.unique(new IntegerBelowThanNode(n.index(), arrayLength)), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, n.leafGraphId());
 
         graph.addBeforeFixed(n, arrayLength);
         return guard;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed May 23 11:55:31 2012 +0200
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.hotspot.snippets;
 import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*;
+import static com.oracle.graal.snippets.SnippetTemplate.*;
 
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.*;
 
 import sun.misc.*;
 
@@ -33,6 +35,7 @@
 import com.oracle.graal.graph.Node.Fold;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.ri.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
@@ -52,11 +55,12 @@
      * @param object the object whose type is being checked against {@code hub}
      * @param hintHubs the hubs of objects that have been profiled during previous executions
      * @param hintsAreExact specifies if {@code hintHubs} contains all subtypes of {@code hub}
+     * @param checkNull specifies if {@code object} may be null
      * @return {@code object} if the type check succeeds
      * @throws ClassCastException if the type check fails
      */
     @Snippet
-    public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) {
+    public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, @SuppressWarnings("unused") Counter ignore) {
         if (object == null) {
             return object;
         }
@@ -108,7 +112,7 @@
         /**
          * Increments this counter if counters are enabled. The body of this method has been carefully crafted
          * such that it contains no safepoints and no calls, neither of which are permissible in a snippet.
-         * Also, increments are not guaranteed to be atomic but that's acceptable for a counter like this.
+         * Also, increments are not guaranteed to be atomic which is acceptable for a counter.
          */
         void inc() {
             if (ENABLED) {
@@ -120,11 +124,8 @@
         static final boolean ENABLED = GraalOptions.CheckcastCounters;
     }
 
-    /**
-     * @see #checkcast(Object, Object, Object[], boolean)
-     */
     @Snippet
-    public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, Counter noHintsCounter) {
+    public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, @SuppressWarnings("unused") boolean checkNull, Counter noHintsCounter) {
         if (object == null) {
             isNull.inc();
             return object;
@@ -169,11 +170,6 @@
         return CompilerImpl.getInstance().getConfig().hubOffset;
     }
 
-    @Fold
-    private static boolean isInterface(RiResolvedType type) {
-        return type.isInterface();
-    }
-
     public static void printCounter(PrintStream out, Counter c, long total) {
         double percent = total == 0D ? 0D : ((double) (c.count * 100)) / total;
         out.println(String.format("%16s: %5.2f%%%10d  // %s", c.name(), percent, c.count, c.description));
@@ -208,4 +204,55 @@
             printCounter(out, c, total);
         }
     }
+
+    /**
+     * Templates for partially specialized checkcast snippet graphs.
+     */
+    public static class Templates {
+
+        private final ConcurrentHashMap<Integer, SnippetTemplate> templates;
+        private final RiResolvedMethod method;
+        private final RiRuntime runtime;
+
+        public Templates(RiRuntime runtime) {
+            this.runtime = runtime;
+            this.templates = new ConcurrentHashMap<>();
+            try {
+                Class[] parameterTypes = {Object.class, Object.class, Object[].class, boolean.class, boolean.class, Counter.class};
+                String name = GraalOptions.CheckcastCounters ? "checkcastWithCounters" : "checkcast";
+                method = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod(name, parameterTypes));
+            } catch (NoSuchMethodException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        /**
+         * Gets a checkcast snippet specialized for a given set od inputs.
+         */
+        public SnippetTemplate get(int nHints, boolean isExact, boolean checkNull, Counter noHintsCounter) {
+            Integer key = key(nHints, isExact, checkNull);
+            SnippetTemplate result = templates.get(key);
+            if (result == null) {
+                HotSpotKlassOop[] hints = new HotSpotKlassOop[nHints];
+                Arrays.fill(hints, new HotSpotKlassOop(null, Templates.class));
+                result = SnippetTemplate.create(runtime, method, _, _, hints, isExact, checkNull, noHintsCounter);
+                templates.put(key, result);
+            }
+            return result;
+        }
+
+        /**
+         * Creates a canonical key for a combination of specialization parameters.
+         */
+        private static Integer key(int nHints, boolean isExact, boolean checkNull) {
+            int key = nHints << 2;
+            if (isExact) {
+                key |= 2;
+            }
+            if (checkNull) {
+                key |= 1;
+            }
+            return key;
+        }
+    }
 }
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 23 11:55:31 2012 +0200
@@ -516,10 +516,32 @@
             probability = 0.5;
         }
 
-        CompareNode condition = currentGraph.unique(new CompareNode(x, cond, y));
+        // the mirroring and negation operations get the condition into canonical form
+        boolean mirror = cond.canonicalMirror();
+        boolean negate = cond.canonicalNegate();
+
+        ValueNode a = mirror ? y : x;
+        ValueNode b = mirror ? x : y;
+
+        CompareNode condition;
+        assert !a.kind().isFloatOrDouble();
+        if (cond == Condition.EQ || cond == Condition.NE) {
+            if (a.kind() == CiKind.Object) {
+                condition = new ObjectEqualsNode(a, b);
+            } else {
+                condition = new IntegerEqualsNode(a, b);
+            }
+        } else {
+            assert a.kind() != CiKind.Object && !cond.isUnsigned();
+            condition = new IntegerLessThanNode(a, b);
+        }
+        condition = currentGraph.unique(condition);
+
         BeginNode trueSuccessor = createBlockTarget(probability, trueBlock, frameState);
         BeginNode falseSuccessor = createBlockTarget(1 - probability, falseBlock, frameState);
-        append(currentGraph.add(new IfNode(condition, trueSuccessor, falseSuccessor, probability)));
+
+        IfNode ifNode = negate ? new IfNode(condition, falseSuccessor, trueSuccessor, 1 - probability) : new IfNode(condition, trueSuccessor, falseSuccessor, probability);
+        append(currentGraph.add(ifNode));
     }
 
     private void genIfZero(Condition cond) {
@@ -543,7 +565,7 @@
 
     private void genThrow() {
         ValueNode exception = frameState.apop();
-        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new NullCheckNode(exception, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, graphId));
+        FixedGuardNode node = currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(exception)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, true, graphId));
         append(node);
         append(handleException(exception, bci()));
     }
@@ -613,7 +635,7 @@
             frameState.apush(checkCast);
         } else {
             ValueNode object = frameState.apop();
-            append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(object, Condition.EQ, ConstantNode.forObject(null, runtime, currentGraph))), RiDeoptReason.Unresolved, RiDeoptAction.InvalidateRecompile, graphId)));
+            append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IsNullNode(object)), RiDeoptReason.Unresolved, RiDeoptAction.InvalidateRecompile, graphId)));
             frameState.apush(appendConstant(CiConstant.NULL_OBJECT));
         }
     }
@@ -625,14 +647,14 @@
         if (type instanceof RiResolvedType) {
             RiResolvedType resolvedType = (RiResolvedType) type;
             ConstantNode hub = appendConstant(resolvedType.getEncoding(RiType.Representation.ObjectHub));
-            InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, getProfileForTypeCheck(resolvedType), false);
+            InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, getProfileForTypeCheck(resolvedType));
             frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph)));
         } else {
-            BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
+            BlockPlaceholderNode successor = currentGraph.add(new BlockPlaceholderNode());
             DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, RiDeoptReason.Unresolved, graphId));
-            IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(object, true)), trueSucc, deopt, 1));
+            IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(object)), successor, deopt, 0));
             append(ifNode);
-            lastInstr = trueSucc;
+            lastInstr = successor;
             frameState.ipush(appendConstant(CiConstant.INT_0));
         }
     }
@@ -734,18 +756,18 @@
     private void emitNullCheck(ValueNode receiver) {
         BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
         BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode());
-        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new NullCheckNode(receiver, false)), trueSucc, falseSucc, 1));
+        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IsNullNode(receiver)), trueSucc, falseSucc, 1));
 
         append(ifNode);
-        lastInstr = trueSucc;
+        lastInstr = falseSucc;
 
         if (GraalOptions.OmitHotExceptionStacktrace) {
             ValueNode exception = ConstantNode.forObject(new NullPointerException(), runtime, currentGraph);
-            falseSucc.setNext(handleException(exception, bci()));
+            trueSucc.setNext(handleException(exception, bci()));
         } else {
             RuntimeCallNode call = currentGraph.add(new RuntimeCallNode(CiRuntimeCall.CreateNullPointerException));
             call.setStateAfter(frameState.create(bci()));
-            falseSucc.setNext(call);
+            trueSucc.setNext(call);
             call.setNext(handleException(call, bci()));
         }
     }
@@ -753,7 +775,7 @@
     private void emitBoundsCheck(ValueNode index, ValueNode length) {
         BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
         BlockPlaceholderNode falseSucc = currentGraph.add(new BlockPlaceholderNode());
-        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new CompareNode(index, Condition.BT, length)), trueSucc, falseSucc, 1));
+        IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new IntegerBelowThanNode(index, length)), trueSucc, falseSucc, 1));
 
         append(ifNode);
         lastInstr = trueSucc;
@@ -1023,7 +1045,7 @@
         ValueNode local = frameState.loadLocal(localIndex);
         JsrScope scope = currentBlock.jsrScope;
         int retAddress = scope.nextReturnAddress();
-        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new CompareNode(local, Condition.EQ, ConstantNode.forJsr(retAddress, currentGraph))), RiDeoptReason.JavaSubroutineMismatch, RiDeoptAction.InvalidateReprofile, graphId)));
+        append(currentGraph.add(new FixedGuardNode(currentGraph.unique(new IntegerEqualsNode(local, ConstantNode.forJsr(retAddress, currentGraph))), RiDeoptReason.JavaSubroutineMismatch, RiDeoptAction.InvalidateReprofile, graphId)));
         if (!successor.jsrScope.equals(scope.pop())) {
             throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)");
         }
@@ -1391,7 +1413,7 @@
             FixedNode catchSuccessor = createTarget(block.successors.get(0), frameState);
             FixedNode nextDispatch = createTarget(nextBlock, frameState);
             ValueNode exception = frameState.stackAt(0);
-            IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new InstanceOfNode(typeInstruction, (RiResolvedType) catchType, exception, false)), catchSuccessor, nextDispatch, 0.5));
+            IfNode ifNode = currentGraph.add(new IfNode(currentGraph.unique(new InstanceOfNode(typeInstruction, (RiResolvedType) catchType, exception)), catchSuccessor, nextDispatch, 0.5));
             append(ifNode);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Wed May 23 11:55:31 2012 +0200
@@ -23,13 +23,16 @@
 package com.oracle.graal.cri;
 
 import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
 public interface CiLoweringTool {
     GraalRuntime getRuntime();
     Node getGuardAnchor();
+    Node createNullCheckGuard(ValueNode object, long leafGraphId);
     Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId);
+    Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId);
     CiAssumptions assumptions();
 }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BooleanNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BooleanNode.java	Wed May 23 11:55:31 2012 +0200
@@ -24,6 +24,7 @@
 
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 
@@ -37,5 +38,13 @@
         super(stamp, dependencies);
     }
 
-    public abstract BooleanNode negate();
+    /**
+     * Tells all usages of this node to negate their effect. For example, IfNodes should switch their true and false successors.
+     */
+    public void negateUsages() {
+        for (Node n : usages().snapshot()) {
+            assert n instanceof Negatable;
+            ((Negatable) n).negate();
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Wed May 23 11:55:31 2012 +0200
@@ -227,9 +227,4 @@
             return super.toString(verbosity);
         }
     }
-
-    @Override
-    public BooleanNode negate() {
-        return ConstantNode.forBoolean(!value.asBoolean(), graph());
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed May 23 11:55:31 2012 +0200
@@ -28,64 +28,76 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ri.*;
 
-public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType {
+public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType, Negatable {
 
-    @Input private final NodeInputList<BooleanNode> conditions;
+    @Input private BooleanNode condition;
     private final RiDeoptReason deoptReason;
     private final RiDeoptAction action;
+    private boolean negated;
     private final long leafGraphId;
 
+    public BooleanNode condition() {
+        return condition;
+    }
+
+    public void setCondition(BooleanNode x) {
+        updateUsages(condition, x);
+        condition = x;
+    }
+
     public FixedGuardNode(BooleanNode condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId) {
+        this(condition, deoptReason, action, false, leafGraphId);
+    }
+
+    public FixedGuardNode(BooleanNode condition, RiDeoptReason deoptReason, RiDeoptAction action, boolean negated, long leafGraphId) {
         super(StampFactory.illegal());
         this.action = action;
+        this.negated = negated;
         this.leafGraphId = leafGraphId;
-        this.conditions = new NodeInputList<>(this, new BooleanNode[] {condition});
+        this.condition = condition;
         this.deoptReason = deoptReason;
     }
 
     @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name && negated) {
+            return "!" + super.toString(verbosity);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
-        for (BooleanNode condition : conditions()) {
-            gen.emitGuardCheck(condition, deoptReason, action, leafGraphId);
-        }
-    }
-
-    public void addCondition(BooleanNode x) {
-        conditions.add(x);
-    }
-
-    public NodeInputList<BooleanNode> conditions() {
-        return conditions;
+        gen.emitGuardCheck(condition, deoptReason, action, negated, leafGraphId);
     }
 
     @Override
     public void simplify(SimplifierTool tool) {
-        for (BooleanNode n : conditions.snapshot()) {
-            if (n instanceof ConstantNode) {
-                ConstantNode c = (ConstantNode) n;
-                if (c.asConstant().asBoolean()) {
-                    conditions.remove(n);
-                } else {
-                    FixedNode next = this.next();
-                    if (next != null) {
-                        tool.deleteBranch(next);
-                    }
-                    setNext(graph().add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, deoptReason, leafGraphId)));
-                    return;
+        if (condition instanceof ConstantNode) {
+            ConstantNode c = (ConstantNode) condition;
+            if (c.asConstant().asBoolean() != negated) {
+                ((StructuredGraph) graph()).removeFixed(this);
+            } else {
+                FixedNode next = this.next();
+                if (next != null) {
+                    tool.deleteBranch(next);
                 }
+                setNext(graph().add(new DeoptimizeNode(RiDeoptAction.InvalidateRecompile, deoptReason, leafGraphId)));
+                return;
             }
         }
-        if (conditions.isEmpty()) {
-            ((StructuredGraph) graph()).removeFixed(this);
-        }
     }
 
     @Override
     public void lower(CiLoweringTool tool) {
         AnchorNode newAnchor = graph().add(new AnchorNode());
-        for (BooleanNode b : conditions) {
-            newAnchor.dependencies().add(tool.createGuard(b, deoptReason, action, leafGraphId));
-        }
+        newAnchor.dependencies().add(tool.createGuard(condition, deoptReason, action, negated, leafGraphId));
         ((StructuredGraph) graph()).replaceFixedWithFixed(this, newAnchor);
     }
+
+    @Override
+    public void negate() {
+        negated = !negated;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Wed May 23 11:55:31 2012 +0200
@@ -40,12 +40,13 @@
  * maximum flexibility for the guard node and guarantees that deoptimization occurs only if the control flow would have
  * reached the guarded node (without taking exceptions into account).
  */
-public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType {
+public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType, Negatable {
 
     @Input private BooleanNode condition;
     @Input(notDataflow = true) private FixedNode anchor;
     private final RiDeoptReason reason;
     private final RiDeoptAction action;
+    private boolean negated;
     private final long leafGraphId;
 
     public FixedNode anchor() {
@@ -69,6 +70,10 @@
         condition = x;
     }
 
+    public boolean negated() {
+        return negated;
+    }
+
     public RiDeoptReason reason() {
         return reason;
     }
@@ -77,25 +82,35 @@
         return action;
     }
 
-    public GuardNode(BooleanNode condition, FixedNode anchor, RiDeoptReason reason, RiDeoptAction action, long leafGraphId) {
+    public GuardNode(BooleanNode condition, FixedNode anchor, RiDeoptReason reason, RiDeoptAction action, boolean negated, long leafGraphId) {
         super(StampFactory.illegal());
         this.condition = condition;
         this.anchor = anchor;
         this.reason = reason;
         this.action = action;
+        this.negated = negated;
         this.leafGraphId = leafGraphId;
     }
 
     @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name && negated) {
+            return "!" + super.toString(verbosity);
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
-        gen.emitGuardCheck(condition(), reason(), action(), leafGraphId);
+        gen.emitGuardCheck(condition(), reason(), action(), negated(), leafGraphId);
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         if (condition() instanceof ConstantNode) {
             ConstantNode c = (ConstantNode) condition();
-            if (c.asConstant().asBoolean()) {
+            if (c.asConstant().asBoolean() != negated) {
                 if (!dependencies().isEmpty()) {
                     for (Node usage : usages()) {
                         if (usage instanceof ValueNode) {
@@ -116,4 +131,9 @@
             ((ConditionalTypeFeedbackProvider) condition).typeFeedback(tool);
         }
     }
+
+    @Override
+    public void negate() {
+        negated = !negated;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Wed May 23 11:55:31 2012 +0200
@@ -33,12 +33,10 @@
  * The {@code IfNode} represents a branch that can go one of two directions depending on the outcome of a
  * comparison.
  */
-public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, SplitTypeFeedbackProvider {
+public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, SplitTypeFeedbackProvider, Negatable {
     public static final int TRUE_EDGE = 0;
     public static final int FALSE_EDGE = 1;
 
-    private static final BeginNode[] EMPTY_IF_SUCCESSORS = new BeginNode[] {null, null};
-
     @Input private BooleanNode compare;
 
     public BooleanNode compare() {
@@ -55,11 +53,6 @@
         this.compare = condition;
     }
 
-    public IfNode(BooleanNode condition, double probability) {
-        super(StampFactory.illegal(), EMPTY_IF_SUCCESSORS, new double[] {probability, 1 - probability});
-        this.compare = condition;
-    }
-
     /**
      * Gets the true successor.
      *
@@ -193,4 +186,17 @@
             ((ConditionalTypeFeedbackProvider) compare).typeFeedback(blockSuccessor == TRUE_EDGE ? tool : tool.negate());
         }
     }
+
+    @Override
+    public void negate() {
+        BeginNode trueSucc = trueSuccessor();
+        BeginNode falseSucc = falseSuccessor();
+        setTrueSuccessor(null);
+        setFalseSuccessor(null);
+        setTrueSuccessor(falseSucc);
+        setFalseSuccessor(trueSucc);
+        double prop = branchProbability[TRUE_EDGE];
+        branchProbability[TRUE_EDGE] = branchProbability[FALSE_EDGE];
+        branchProbability[FALSE_EDGE] = prop;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed May 23 11:55:31 2012 +0200
@@ -81,7 +81,7 @@
         int predIndex = phiPredecessorIndex(pred);
         assert predIndex != -1;
         deleteEnd(pred);
-        for (PhiNode phi : phis()) {
+        for (PhiNode phi : phis().snapshot()) {
             ValueNode removedValue = phi.valueAt(predIndex);
             phi.removeInput(predIndex);
             if (removedValue != null && removedValue.isAlive() && removedValue.usages().isEmpty() && GraphUtil.isFloatingNode().apply(removedValue)) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java	Wed May 23 11:55:31 2012 +0200
@@ -22,12 +22,12 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.types.*;
-import com.oracle.graal.nodes.type.*;
 
 /* TODO (thomaswue/gdub) For high-level optimization purpose the compare node should be a boolean *value* (it is currently only a helper node)
  * But in the back-end the comparison should not always be materialized (for example in x86 the comparison result will not be in a register but in a flag)
@@ -35,14 +35,11 @@
  * Compare should probably be made a value (so that it can be canonicalized for example) and in later stages some Compare usage should be transformed
  * into variants that do not materialize the value (CompareIf, CompareGuard...)
  */
-public final class CompareNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable {
+public abstract class CompareNode extends BooleanNode implements Canonicalizable, LIRLowerable {
 
     @Input private ValueNode x;
     @Input private ValueNode y;
 
-    private final Condition condition;
-    private final boolean unorderedIsTrue;
-
     public ValueNode x() {
         return x;
     }
@@ -55,27 +52,11 @@
      * Constructs a new Compare instruction.
      *
      * @param x the instruction producing the first input to the instruction
-     * @param condition the condition (comparison operation)
      * @param y the instruction that produces the second input to this instruction
-     * @param graph
      */
-    public CompareNode(ValueNode x, Condition condition, ValueNode y) {
-        this(x, condition, false, y);
-    }
-
-    /**
-     * Constructs a new Compare instruction.
-     *
-     * @param x the instruction producing the first input to the instruction
-     * @param condition the condition (comparison operation)
-     * @param y the instruction that produces the second input to this instruction
-     * @param graph
-     */
-    public CompareNode(ValueNode x, Condition condition, boolean unorderedIsTrue, ValueNode y) {
+    public CompareNode(ValueNode x, ValueNode y) {
         super(StampFactory.illegal());
         assert (x == null && y == null) || x.kind() == y.kind();
-        this.condition = condition;
-        this.unorderedIsTrue = unorderedIsTrue;
         this.x = x;
         this.y = y;
     }
@@ -85,44 +66,27 @@
      *
      * @return the condition
      */
-    public Condition condition() {
-        return condition;
-    }
+    public abstract Condition condition();
 
     /**
-     * Checks whether unordered inputs mean true or false.
+     * Checks whether unordered inputs mean true or false (only applies to float operations).
      *
      * @return {@code true} if unordered inputs produce true
      */
-    public boolean unorderedIsTrue() {
-        return unorderedIsTrue;
-    }
-
-    @Override
-    public BooleanNode negate() {
-        return graph().unique(new CompareNode(x(), condition.negate(), !unorderedIsTrue, y()));
-    }
+    public abstract boolean unorderedIsTrue();
 
     @Override
     public void generate(LIRGeneratorTool gen) {
     }
 
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name) {
-            return super.toString(Verbosity.Name) + " " + condition.operator;
-        } else {
-            return super.toString(verbosity);
-        }
-    }
 
-    private ValueNode optimizeMaterialize(CiConstant constant, MaterializeNode materializeNode, RiRuntime runtime) {
+    private ValueNode optimizeMaterialize(CiConstant constant, MaterializeNode materializeNode, RiRuntime runtime, Condition cond) {
         CiConstant trueConstant = materializeNode.trueValue().asConstant();
         CiConstant falseConstant = materializeNode.falseValue().asConstant();
 
         if (falseConstant != null && trueConstant != null) {
-            Boolean trueResult = condition().foldCondition(trueConstant, constant, runtime, unorderedIsTrue());
-            Boolean falseResult = condition().foldCondition(falseConstant, constant, runtime, unorderedIsTrue());
+            Boolean trueResult = cond.foldCondition(trueConstant, constant, runtime, unorderedIsTrue());
+            Boolean falseResult = cond.foldCondition(falseConstant, constant, runtime, unorderedIsTrue());
 
             if (trueResult != null && falseResult != null) {
                 boolean trueUnboxedResult = trueResult;
@@ -135,7 +99,8 @@
                         return materializeNode.condition();
                     } else {
                         assert falseUnboxedResult == true;
-                        return materializeNode.condition().negate();
+                        negateUsages();
+                        return materializeNode.condition();
 
                     }
                 }
@@ -144,160 +109,27 @@
         return this;
     }
 
-    private ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode) {
-        if (constant.kind == CiKind.Int && constant.asInt() == 0) {
-            Condition cond = condition();
-            boolean isLess = cond == Condition.LE || cond == Condition.LT || cond == Condition.BE || cond == Condition.BT;
-            boolean canonUnorderedIsTrue = cond != Condition.EQ && (cond == Condition.NE || !(isLess ^ normalizeNode.isUnorderedLess));
-            CompareNode result = graph().unique(new CompareNode(normalizeNode.x(), cond, canonUnorderedIsTrue, normalizeNode.y()));
-            return result;
-        }
-        return this;
+    protected ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+        throw new GraalInternalError("NormalizeCompareNode connected to %s (%s %s %s)", this, constant, normalizeNode, mirrored);
     }
 
-    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (x().isConstant() && !y().isConstant()) { // move constants to the left (y)
-            return graph().unique(new CompareNode(y(), condition.mirror(), unorderedIsTrue(), x()));
-        } else if (x().isConstant() && y().isConstant()) {
-            CiConstant constX = x().asConstant();
-            CiConstant constY = y().asConstant();
-            Boolean result = condition().foldCondition(constX, constY, tool.runtime(), unorderedIsTrue());
-            if (result != null) {
-                return ConstantNode.forBoolean(result, graph());
-            }
-        }
-
-        if (y().isConstant()) {
-            if (x() instanceof MaterializeNode) {
-                return optimizeMaterialize(y().asConstant(), (MaterializeNode) x(), tool.runtime());
-            } else if (x() instanceof NormalizeCompareNode) {
-                return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x());
-            }
+        if (x().isConstant() && y().isConstant()) {
+            return ConstantNode.forBoolean(condition().foldCondition(x().asConstant(), y().asConstant(), tool.runtime(), unorderedIsTrue()), graph());
         }
-
-        if (x() == y() && x().kind() != CiKind.Float && x().kind() != CiKind.Double) {
-            return ConstantNode.forBoolean(condition().check(1, 1), graph());
-        }
-        if ((condition == Condition.NE || condition == Condition.EQ) && x().kind() == CiKind.Object) {
-            ValueNode object = null;
-            if (x().isNullConstant()) {
-                object = y();
-            } else if (y().isNullConstant()) {
-                object = x();
+        if (x().isConstant()) {
+            if (y() instanceof MaterializeNode) {
+                return optimizeMaterialize(x().asConstant(), (MaterializeNode) y(), tool.runtime(), condition().mirror());
+            } else if (y() instanceof NormalizeCompareNode) {
+                return optimizeNormalizeCmp(x().asConstant(), (NormalizeCompareNode) y(), true);
             }
-            if (object != null) {
-                return graph().unique(new NullCheckNode(object, condition == Condition.EQ));
-            } else {
-                Stamp xStamp = x.stamp();
-                Stamp yStamp = y.stamp();
-                if (xStamp.alwaysDistinct(yStamp)) {
-                    return ConstantNode.forBoolean(condition == Condition.NE, graph());
-                }
+        } else if (y().isConstant()) {
+            if (x() instanceof MaterializeNode) {
+                return optimizeMaterialize(y().asConstant(), (MaterializeNode) x(), tool.runtime(), condition());
+            } else if (x() instanceof NormalizeCompareNode) {
+                return optimizeNormalizeCmp(y().asConstant(), (NormalizeCompareNode) x(), false);
             }
         }
         return this;
     }
-
-    @Override
-    public void typeFeedback(TypeFeedbackTool tool) {
-        CiKind kind = x().kind();
-        assert y().kind() == kind;
-        if (kind == CiKind.Object) {
-            assert condition == Condition.EQ || condition == Condition.NE;
-            if (y().isConstant() && !x().isConstant()) {
-                tool.addObject(x()).constantBound(condition, y().asConstant());
-            } else if (x().isConstant() && !y().isConstant()) {
-                tool.addObject(y()).constantBound(condition.mirror(), x().asConstant());
-            } else if (!x().isConstant() && !y.isConstant()) {
-                tool.addObject(x()).valueBound(condition, y());
-                tool.addObject(y()).valueBound(condition.mirror(), x());
-            } else {
-                // both are constant, this should be canonicalized...
-            }
-        } else if (kind == CiKind.Int || kind == CiKind.Long) {
-            if (y().isConstant() && !x().isConstant()) {
-                tool.addScalar(x()).constantBound(condition, y().asConstant());
-            } else if (x().isConstant() && !y().isConstant()) {
-                tool.addScalar(y()).constantBound(condition.mirror(), x().asConstant());
-            } else if (!x().isConstant() && !y.isConstant()) {
-                tool.addScalar(x()).valueBound(condition, y(), tool.queryScalar(y()));
-                tool.addScalar(y()).valueBound(condition.mirror(), x(), tool.queryScalar(x()));
-            } else {
-                // both are constant, this should be canonicalized...
-            }
-        } else if (kind == CiKind.Float || kind == CiKind.Double) {
-            // nothing yet...
-        }
-    }
-
-    @Override
-    public Result canonical(TypeFeedbackTool tool) {
-        CiKind kind = x().kind();
-        if (kind == CiKind.Int || kind == CiKind.Long) {
-            ScalarTypeQuery queryX = tool.queryScalar(x());
-            if (y().isConstant() && !x().isConstant()) {
-                if (queryX.constantBound(condition, y().asConstant())) {
-                    return new Result(ConstantNode.forBoolean(true, graph()), queryX);
-                } else if (queryX.constantBound(condition.negate(), y().asConstant())) {
-                    return new Result(ConstantNode.forBoolean(false, graph()), queryX);
-                }
-            } else {
-                ScalarTypeQuery queryY = tool.queryScalar(y());
-                if (x().isConstant() && !y().isConstant()) {
-                    if (queryY.constantBound(condition.mirror(), x().asConstant())) {
-                        return new Result(ConstantNode.forBoolean(true, graph()), queryY);
-                    } else if (queryY.constantBound(condition.mirror().negate(), x().asConstant())) {
-                        return new Result(ConstantNode.forBoolean(false, graph()), queryY);
-                    }
-                } else if (!x().isConstant() && !y.isConstant()) {
-                    if (condition == Condition.BT || condition == Condition.BE) {
-                        if (queryY.constantBound(Condition.GE, new CiConstant(kind, 0))) {
-                            if (queryX.constantBound(Condition.GE, new CiConstant(kind, 0))) {
-                                if (queryX.valueBound(condition == Condition.BT ? Condition.LT : Condition.LE, y())) {
-                                    return new Result(ConstantNode.forBoolean(true, graph()), queryX, queryY);
-                                }
-                            }
-                        }
-                    }
-
-                    if (queryX.valueBound(condition, y())) {
-                        return new Result(ConstantNode.forBoolean(true, graph()), queryX);
-                    } else if (queryX.valueBound(condition.negate(), y())) {
-                        return new Result(ConstantNode.forBoolean(false, graph()), queryX);
-                    }
-                } else {
-                    // both are constant, this should be canonicalized...
-                }
-            }
-        } else  if (kind == CiKind.Object) {
-            assert condition == Condition.EQ || condition == Condition.NE;
-            ObjectTypeQuery queryX = tool.queryObject(x());
-            if (y().isConstant() && !x().isConstant()) {
-                if (queryX.constantBound(condition, y().asConstant())) {
-                    return new Result(ConstantNode.forBoolean(true, graph()), queryX);
-                } else if (queryX.constantBound(condition.negate(), y().asConstant())) {
-                    return new Result(ConstantNode.forBoolean(false, graph()), queryX);
-                }
-            } else {
-                ObjectTypeQuery queryY = tool.queryObject(y());
-                if (x().isConstant() && !y().isConstant()) {
-                    if (queryY.constantBound(condition.mirror(), x().asConstant())) {
-                        return new Result(ConstantNode.forBoolean(true, graph()), queryY);
-                    } else if (queryY.constantBound(condition.mirror().negate(), x().asConstant())) {
-                        return new Result(ConstantNode.forBoolean(false, graph()), queryY);
-                    }
-                } else if (!x().isConstant() && !y.isConstant()) {
-                    if (queryX.valueBound(condition, y())) {
-                        return new Result(ConstantNode.forBoolean(true, graph()), queryX);
-                    } else if (queryX.valueBound(condition.negate(), y())) {
-                        return new Result(ConstantNode.forBoolean(false, graph()), queryX);
-                    }
-                } else {
-                    // both are constant, this should be canonicalized...
-                }
-            }
-        }
-        return null;
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/Condition.java	Wed May 23 11:55:31 2012 +0200
@@ -224,6 +224,13 @@
     }
 
     /**
+     * Returns true if this condition represents an unsigned comparison. EQ and NE are not considered to be unsigned.
+     */
+    public final boolean isUnsigned() {
+        return this == Condition.BT || this == Condition.BE || this == Condition.AT || this == Condition.AE;
+    }
+
+    /**
      * Checks if this conditional operation is commutative.
      * @return {@code true} if this operation is commutative
      */
@@ -239,6 +246,19 @@
      * @return {@link Boolean#TRUE} if the comparison is known to be true,
      * {@link Boolean#FALSE} if the comparison is known to be false
      */
+    public boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime) {
+        assert !lt.kind.isFloatOrDouble() && !rt.kind.isFloatOrDouble();
+        return foldCondition(lt, rt, runtime, false);
+    }
+
+    /**
+     * Attempts to fold a comparison between two constants and return the result.
+     * @param lt the constant on the left side of the comparison
+     * @param rt the constant on the right side of the comparison
+     * @param runtime the RiRuntime (might be needed to compare runtime-specific types)
+     * @param unorderedIsTrue true if an undecided float comparison should result in "true"
+     * @return true if the comparison is known to be true, false if the comparison is known to be false
+     */
     public boolean foldCondition(CiConstant lt, CiConstant rt, RiRuntime runtime, boolean unorderedIsTrue) {
         switch (lt.kind) {
             case Boolean:
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ConditionalNode.java	Wed May 23 11:55:31 2012 +0200
@@ -29,7 +29,7 @@
  * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note that these nodes are not
  * built directly from the bytecode but are introduced by canonicalization.
  */
-public class ConditionalNode extends BinaryNode implements Canonicalizable, LIRLowerable {
+public class ConditionalNode extends BinaryNode implements Canonicalizable, LIRLowerable, Negatable {
 
     @Input private BooleanNode condition;
 
@@ -72,4 +72,9 @@
     public void generate(LIRGeneratorTool generator) {
         generator.emitConditional(this);
     }
+
+    @Override
+    public void negate() {
+        ((StructuredGraph) graph()).replaceFloating(this, graph().unique(new ConditionalNode(condition, falseValue(), trueValue())));
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatEqualsNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+@NodeInfo(shortName = "==")
+public final class FloatEqualsNode extends CompareNode {
+
+    /**
+     * Constructs a new floating point equality comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    public FloatEqualsNode(ValueNode x, ValueNode y) {
+        super(x, y);
+        assert x.kind().isFloatOrDouble();
+        assert y.kind().isFloatOrDouble();
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.EQ;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return false;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatLessThanNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+
+@NodeInfo(shortName = "<")
+public final class FloatLessThanNode extends CompareNode {
+
+    private final boolean unorderedIsTrue;
+
+    /**
+     * Constructs a new floating point comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     * @param unorderedIsTrue whether a comparison that is undecided (involving NaNs, etc.) leads to a "true" result
+     */
+    public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
+        super(x, y);
+        assert x.kind().isFloatOrDouble();
+        assert y.kind().isFloatOrDouble();
+        this.unorderedIsTrue = unorderedIsTrue;
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.LT;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return unorderedIsTrue;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x() == y() && !unorderedIsTrue()) {
+            return ConstantNode.forBoolean(false, graph());
+        }
+        return super.canonical(tool);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerBelowThanNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.max.cri.ci.*;
+
+@NodeInfo(shortName = "|<|")
+public final class IntegerBelowThanNode extends CompareNode {
+
+    /**
+     * Constructs a new unsigned integer comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    public IntegerBelowThanNode(ValueNode x, ValueNode y) {
+        super(x, y);
+        assert !x.kind().isFloatOrDouble() && x.kind() != CiKind.Object;
+        assert !y.kind().isFloatOrDouble() && y.kind() != CiKind.Object;
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.BT;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x() == y()) {
+            return ConstantNode.forBoolean(false, graph());
+        }
+        return super.canonical(tool);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerEqualsNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.max.cri.ci.*;
+
+@NodeInfo(shortName = "==")
+public final class IntegerEqualsNode extends CompareNode {
+
+    /**
+     * Constructs a new integer equality comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    public IntegerEqualsNode(ValueNode x, ValueNode y) {
+        super(x, y);
+        assert !x.kind().isFloatOrDouble() && x.kind() != CiKind.Object;
+        assert !y.kind().isFloatOrDouble() && y.kind() != CiKind.Object;
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.EQ;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return false;
+    }
+
+    @Override
+    protected ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+        if (constant.kind == CiKind.Int && constant.asInt() == 0) {
+            ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x();
+            ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y();
+
+            if (normalizeNode.x().kind().isFloatOrDouble()) {
+                return graph().unique(new FloatEqualsNode(a, b));
+            } else {
+                return graph().unique(new IntegerEqualsNode(a, b));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x() == y()) {
+            return ConstantNode.forBoolean(true, graph());
+        }
+        return super.canonical(tool);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerLessThanNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.max.cri.ci.*;
+
+@NodeInfo(shortName = "<")
+public final class IntegerLessThanNode extends CompareNode {
+
+    /**
+     * Constructs a new integer comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    public IntegerLessThanNode(ValueNode x, ValueNode y) {
+        super(x, y);
+        assert !x.kind().isFloatOrDouble() && x.kind() != CiKind.Object;
+        assert !y.kind().isFloatOrDouble() && y.kind() != CiKind.Object;
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.LT;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return false;
+    }
+
+    @Override
+    protected ValueNode optimizeNormalizeCmp(CiConstant constant, NormalizeCompareNode normalizeNode, boolean mirrored) {
+        assert condition() == Condition.LT;
+        if (constant.kind == CiKind.Int && constant.asInt() == 0) {
+            ValueNode a = mirrored ? normalizeNode.y() : normalizeNode.x();
+            ValueNode b = mirrored ? normalizeNode.x() : normalizeNode.y();
+
+            if (normalizeNode.x().kind().isFloatOrDouble()) {
+                return graph().unique(new FloatLessThanNode(a, b, mirrored ^ normalizeNode.isUnorderedLess));
+            } else {
+                return graph().unique(new IntegerLessThanNode(a, b));
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x() == y()) {
+            return ConstantNode.forBoolean(false, graph());
+        }
+        return super.canonical(tool);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IsNullNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2009, 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.calc;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
+
+/**
+ * An IsNullNode will be true if the supplied value is null, and false if it is non-null.
+ */
+public final class IsNullNode extends BooleanNode implements Canonicalizable, LIRLowerable {
+
+    @Input private ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    /**
+     * Constructs a new IsNullNode instruction.
+     *
+     * @param object the instruction producing the object to check against null
+     */
+    public IsNullNode(ValueNode object) {
+        super(StampFactory.illegal());
+        assert object.kind() == CiKind.Object : object.kind();
+        this.object = object;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool gen) {
+        // Nothing to do.
+    }
+
+    @Override
+    public boolean verify() {
+        assertTrue(object() != null, "is null input must not be null");
+        assertTrue(object().kind().isObject(), "is null input must be an object");
+        return super.verify();
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        CiConstant constant = object().asConstant();
+        if (constant != null) {
+            assert constant.kind == CiKind.Object;
+            return ConstantNode.forBoolean(constant.isNull(), graph());
+        }
+        if (object.stamp().nonNull()) {
+            return ConstantNode.forBoolean(false, graph());
+        }
+        return this;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NegateNode.java	Wed May 23 11:55:31 2012 +0200
@@ -31,8 +31,7 @@
  */
 public final class NegateNode extends FloatingNode implements Canonicalizable, LIRLowerable {
 
-    @Input
-    private ValueNode x;
+    @Input private ValueNode x;
 
     public ValueNode x() {
         return x;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NormalizeCompareNode.java	Wed May 23 11:55:31 2012 +0200
@@ -28,7 +28,8 @@
 import com.oracle.graal.nodes.spi.*;
 
 /**
- * Returns -1, 0, or 1 if either x < y, x == y, or x > y.
+ * Returns -1, 0, or 1 if either x < y, x == y, or x > y. If the comparison is undecided (one of the inputs is NaN), the
+ * result is 1 if isUnorderedLess is false and -1 if isUnorderedLess is true.
  */
 public final class NormalizeCompareNode extends BinaryNode implements Lowerable {
     public final boolean isUnorderedLess;
@@ -48,10 +49,17 @@
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
 
-        CompareNode equalComp = graph.unique(new CompareNode(x(), Condition.EQ, false, y()));
+        BooleanNode equalComp;
+        BooleanNode lessComp;
+        if (x().kind().isFloatOrDouble()) {
+            equalComp = graph.unique(new FloatEqualsNode(x(), y()));
+            lessComp = graph.unique(new FloatLessThanNode(x(), y(), isUnorderedLess));
+        } else {
+            equalComp = graph.unique(new IntegerEqualsNode(x(), y()));
+            lessComp = graph.unique(new IntegerLessThanNode(x(), y()));
+        }
+
         MaterializeNode equalValue = MaterializeNode.create(equalComp, graph, ConstantNode.forInt(0, graph), ConstantNode.forInt(1, graph));
-
-        CompareNode lessComp = graph.unique(new CompareNode(x(), Condition.LT, isUnorderedLess, y()));
         MaterializeNode value =  MaterializeNode.create(lessComp, graph, ConstantNode.forInt(-1, graph), equalValue);
 
         graph.replaceFloating(this, value);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/NullCheckNode.java	Wed May 23 10:09:39 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- * Copyright (c) 2009, 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.calc;
-
-import com.oracle.max.cri.ci.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.spi.types.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * A NullCheckNode will be true if the supplied value is non-null, and false if it is null.
- * This behavior can be inverted by setting {@link #expectedNull} to true.
- */
-public final class NullCheckNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable {
-
-    @Input private ValueNode object;
-    public final boolean expectedNull;
-
-    public ValueNode object() {
-        return object;
-    }
-
-    /**
-     * Constructs a new NullCheck instruction.
-     *
-     * @param object the instruction producing the object to check against null
-     * @param expectedNull True when this node checks that the value is null, false when this node checks for non-null
-     */
-    public NullCheckNode(ValueNode object, boolean expectedNull) {
-        super(StampFactory.illegal());
-        assert object.kind() == CiKind.Object : object.kind();
-        this.object = object;
-        this.expectedNull = expectedNull;
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        // Nothing to do.
-    }
-
-    @Override
-    public boolean verify() {
-        assertTrue(object() != null, "null check input must not be null");
-        assertTrue(object().kind().isObject(), "null check input must be an object");
-        return super.verify();
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        CiConstant constant = object().asConstant();
-        if (constant != null) {
-            assert constant.kind == CiKind.Object;
-            return ConstantNode.forBoolean(constant.isNull() == expectedNull, graph());
-        }
-        if (object.stamp().nonNull()) {
-            return ConstantNode.forBoolean(!expectedNull, graph());
-        }
-        return this;
-    }
-
-    @Override
-    public BooleanNode negate() {
-        return graph().unique(new NullCheckNode(object(), !expectedNull));
-    }
-
-    @Override
-    public void typeFeedback(TypeFeedbackTool tool) {
-        Condition expectedCondition = expectedNull ? Condition.EQ : Condition.NE;
-        tool.addObject(object()).constantBound(expectedCondition, CiConstant.NULL_OBJECT);
-    }
-
-    @Override
-    public Result canonical(TypeFeedbackTool tool) {
-        Condition expectedCondition = expectedNull ? Condition.EQ : Condition.NE;
-        ObjectTypeQuery query = tool.queryObject(object());
-        if (query.constantBound(expectedCondition, CiConstant.NULL_OBJECT)) {
-            return new Result(ConstantNode.forBoolean(true, graph()), query);
-        } else if (query.constantBound(expectedCondition.negate(), CiConstant.NULL_OBJECT)) {
-            return new Result(ConstantNode.forBoolean(false, graph()), query);
-        }
-        return null;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2011, 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.calc;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.max.cri.ci.*;
+
+@NodeInfo(shortName = "==")
+public final class ObjectEqualsNode extends CompareNode {
+
+    /**
+     * Constructs a new object equality comparison node.
+     *
+     * @param x the instruction producing the first input to the instruction
+     * @param y the instruction that produces the second input to this instruction
+     */
+    public ObjectEqualsNode(ValueNode x, ValueNode y) {
+        super(x, y);
+        assert x.kind() == CiKind.Object;
+        assert y.kind() == CiKind.Object;
+    }
+
+    @Override
+    public Condition condition() {
+        return Condition.EQ;
+    }
+
+    @Override
+    public boolean unorderedIsTrue() {
+        return false;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (x() == y()) {
+            return ConstantNode.forBoolean(true, graph());
+        }
+
+        if (x().isNullConstant()) {
+            return graph().unique(new IsNullNode(y()));
+        } else if (y().isNullConstant()) {
+            return graph().unique(new IsNullNode(x()));
+        }
+        if (x().stamp().alwaysDistinct(y().stamp())) {
+            return ConstantNode.forBoolean(false, graph());
+        }
+
+        return super.canonical(tool);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Wed May 23 11:55:31 2012 +0200
@@ -25,11 +25,8 @@
 import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
-import com.oracle.max.cri.ri.*;
-
 
 public class SafeReadNode extends SafeAccessNode implements Lowerable {
 
@@ -41,7 +38,7 @@
     @Override
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        Node guard = tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId());
+        Node guard = tool.createNullCheckGuard(object(), leafGraphId());
         ReadNode read = graph.add(new ReadNode(object(), location(), stamp()));
         read.dependencies().add(guard);
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Wed May 23 11:55:31 2012 +0200
@@ -25,14 +25,11 @@
 import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
 
-
-public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable{
+public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable {
 
     @Input private ValueNode value;
     @Input(notDataflow = true) private FrameState stateAfter;
@@ -63,7 +60,7 @@
     @Override
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        Node guard = tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId());
+        Node guard = tool.createNullCheckGuard(object(), leafGraphId());
         WriteNode write = graph.add(new WriteNode(object(), value(), location()));
         write.dependencies().add(guard);
         graph.replaceFixedWithFixed(this, write);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 23 11:55:31 2012 +0200
@@ -35,16 +35,11 @@
  */
 public final class InstanceOfNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable {
 
-    private final boolean negated;
     @Input private ValueNode object;
     @Input private ValueNode targetClassInstruction;
     private final RiResolvedType targetClass;
     private final RiTypeProfile profile;
 
-    public boolean negated() {
-        return negated;
-    }
-
     /**
      * Constructs a new InstanceOfNode.
      *
@@ -52,17 +47,16 @@
      * @param targetClass the class which is the target of the instanceof check
      * @param object the instruction producing the object input to this instruction
      */
-    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, boolean negated) {
-        this(targetClassInstruction, targetClass, object, null, negated);
+    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) {
+        this(targetClassInstruction, targetClass, object, null);
     }
 
-    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile, boolean negated) {
+    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile) {
         super(StampFactory.illegal());
         this.targetClassInstruction = targetClassInstruction;
         this.targetClass = targetClass;
         this.object = object;
         this.profile = profile;
-        this.negated = negated;
         assert targetClass != null;
     }
 
@@ -81,16 +75,17 @@
             if (subType) {
                 if (object().stamp().nonNull()) {
                     // the instanceOf matches, so return true (or false, for the negated case)
-                    return ConstantNode.forBoolean(!negated, graph());
+                    return ConstantNode.forBoolean(true, graph());
                 } else {
                     // the instanceof matches if the object is non-null, so return true (or false, for the negated case) depending on the null-ness.
-                    return graph().unique(new NullCheckNode(object(), negated));
+                    negateUsages();
+                    return graph().unique(new IsNullNode(object()));
                 }
             } else {
                 // since this type check failed for an exact type we know that it can never succeed at run time.
                 // we also don't care about null values, since they will also make the check fail.
                 // so return false (or true, for the negated case)
-                return ConstantNode.forBoolean(negated, graph());
+                return ConstantNode.forBoolean(false, graph());
             }
         } else {
             RiResolvedType declared = object().declaredType();
@@ -100,10 +95,11 @@
                 if (subType) {
                     if (object().stamp().nonNull()) {
                         // the instanceOf matches, so return true (or false, for the negated case)
-                        return ConstantNode.forBoolean(!negated, graph());
+                        return ConstantNode.forBoolean(true, graph());
                     } else {
                         // the instanceof matches if the object is non-null, so return true (or false, for the negated case) depending on the null-ness.
-                        return graph().unique(new NullCheckNode(object(), negated));
+                        negateUsages();
+                        return graph().unique(new IsNullNode(object()));
                     }
                 } else {
                     // since the subtype comparison was only performed on a declared type we don't really know if it might be true at run time...
@@ -115,7 +111,7 @@
         if (constant != null) {
             assert constant.kind == CiKind.Object;
             if (constant.isNull()) {
-                return ConstantNode.forBoolean(negated, graph());
+                return ConstantNode.forBoolean(false, graph());
             } else {
                 assert false : "non-null constants are always expected to provide an exactType";
             }
@@ -124,40 +120,22 @@
     }
 
     @Override
-    public BooleanNode negate() {
-        return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), profile(), !negated));
-    }
-
-    @Override
     public void typeFeedback(TypeFeedbackTool tool) {
-        if (negated) {
-            tool.addObject(object()).notDeclaredType(targetClass(), true);
-        } else {
-            tool.addObject(object()).declaredType(targetClass(), true);
-        }
-    }
-
-    @Override
-    public String toString(Verbosity verbosity) {
-        if (verbosity == Verbosity.Name && negated) {
-            return "!" + super.toString(Verbosity.Name);
-        } else {
-            return super.toString(verbosity);
-        }
+        tool.addObject(object()).declaredType(targetClass(), true);
     }
 
     @Override
     public Result canonical(TypeFeedbackTool tool) {
         ObjectTypeQuery query = tool.queryObject(object());
         if (query.constantBound(Condition.EQ, CiConstant.NULL_OBJECT)) {
-            return new Result(ConstantNode.forBoolean(negated, graph()), query);
+            return new Result(ConstantNode.forBoolean(false, graph()), query);
         } else if (targetClass() != null) {
             if (query.notDeclaredType(targetClass())) {
-                return new Result(ConstantNode.forBoolean(negated, graph()), query);
+                return new Result(ConstantNode.forBoolean(false, graph()), query);
             }
             if (query.constantBound(Condition.NE, CiConstant.NULL_OBJECT)) {
                 if (query.declaredType(targetClass())) {
-                    return new Result(ConstantNode.forBoolean(!negated, graph()), query);
+                    return new Result(ConstantNode.forBoolean(true, graph()), query);
                 }
             }
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java	Wed May 23 11:55:31 2012 +0200
@@ -77,9 +77,4 @@
         // constants return the correct exactType, so they are handled by the code above
         return this;
     }
-
-    @Override
-    public BooleanNode negate() {
-        throw new Error("unimplemented");
-    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/EscapeOp.java	Wed May 23 11:55:31 2012 +0200
@@ -37,8 +37,8 @@
     public abstract boolean canAnalyze(Node node);
 
     public boolean escape(Node node, Node usage) {
-        if (usage instanceof NullCheckNode) {
-            assert ((NullCheckNode) usage).object() == node;
+        if (usage instanceof IsNullNode) {
+            assert ((IsNullNode) usage).object() == node;
             return false;
         } else if (usage instanceof IsTypeNode) {
             assert ((IsTypeNode) usage).objectClass() == node;
@@ -107,9 +107,9 @@
 
     public void beforeUpdate(Node node, Node usage) {
         // IsNonNullNode and IsTypeNode should have been eliminated by the CanonicalizerPhase, but we can't rely on this
-        if (usage instanceof NullCheckNode) {
-            NullCheckNode x = (NullCheckNode) usage;
-            ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(!x.expectedNull, node.graph()));
+        if (usage instanceof IsNullNode) {
+            IsNullNode x = (IsNullNode) usage;
+            ((StructuredGraph) x.graph()).replaceFloating(x, ConstantNode.forBoolean(false, node.graph()));
         } else if (usage instanceof IsTypeNode) {
             IsTypeNode x = (IsTypeNode) usage;
             assert x.type() == ((ValueNode) node).exactType();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/LIRGeneratorTool.java	Wed May 23 11:55:31 2012 +0200
@@ -88,7 +88,7 @@
 
     public abstract void emitIf(IfNode i);
     public abstract void emitConditional(ConditionalNode i);
-    public abstract void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction deoptAction, long leafGraphId);
+    public abstract void emitGuardCheck(BooleanNode comp, RiDeoptReason deoptReason, RiDeoptAction deoptAction, boolean negated, long leafGraphId);
 
     public abstract void emitLookupSwitch(LookupSwitchNode i);
     public abstract void emitTableSwitch(TableSwitchNode i);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/spi/Negatable.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.spi;
+
+import com.oracle.graal.nodes.*;
+
+/**
+ * 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.
+ */
+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.
+     */
+    void negate();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,344 @@
+/*
+ * 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.snippets;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.compiler.loop.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+
+/**
+ * A snippet template is a graph created by parsing a snippet method and then
+ * specialized by binding constants to some of the snippet arguments and applying
+ * transformations such as canonicalization and loop peeling.
+ */
+public class SnippetTemplate {
+
+    /**
+     * Special value denoting a non-specialized argument.
+     */
+    public static final Object _ = new Object() {
+        @Override
+        public String toString() {
+            return "_";
+        }
+    };
+
+    /**
+     * Creates a snippet template.
+     *
+     * @param runtime
+     * @param method the snippet method to create the initial graph from
+     * @param args the arguments used to specialize the graph
+     */
+    public static SnippetTemplate create(final RiRuntime runtime, final RiResolvedMethod method, final Object... args) {
+        return Debug.scope("SnippetSpecialization", method, new Callable<SnippetTemplate>() {
+            @Override
+            public SnippetTemplate call() throws Exception {
+                assert Modifier.isStatic(method.accessFlags()) : "snippet method must be static: " + method;
+                RiSignature signature = method.signature();
+                assert signature.argumentCount(false) == args.length : "snippet method expects " + signature.argumentCount(false) + " arguments, " + args.length + " given";
+                StructuredGraph snippetGraph = (StructuredGraph) method.compilerStorage().get(Graph.class);
+
+                final Map<CiConstant, CiConstant> constantArrays = new IdentityHashMap<>();
+                IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() {
+                    public boolean apply(CiConstant constant) {
+                        return constantArrays.containsKey(constant);
+                    }
+                };
+
+                // Copy snippet graph, replacing parameters with given args in the process
+                StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
+                IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+                replacements.put(snippetGraph.start(), snippetCopy.start());
+                int localCount = 0;
+                for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) {
+                    int index = local.index();
+                    Object arg = args[index];
+                    if (arg != _) {
+                        CiKind kind = signature.argumentKindAt(index, false);
+                        assert kind.isObject() || (arg != null && kind.toBoxedJavaClass() == arg.getClass()) :
+                            "arg " + index + " for " + method + " has wrong kind: expected " + kind + ", got " + (arg == null ? "null" : arg.getClass().getSimpleName());
+                        CiConstant specializationArg = CiConstant.forBoxed(kind, arg);
+                        if (kind.isObject()) {
+                            assert arg == null || signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().isInstance(arg) :
+                                String.format("argument %d is of wrong type: expected %s, got %s", index, signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().getName(), arg.getClass().getName());
+                            if (arg != null) {
+                                if (arg.getClass().isArray()) {
+                                    constantArrays.put(specializationArg, specializationArg);
+                                }
+                            }
+                        }
+
+                        ConstantNode argNode = ConstantNode.forCiConstant(specializationArg, runtime, snippetCopy);
+                        replacements.put(local, argNode);
+                    }
+                    localCount++;
+                }
+                assert localCount == args.length : "snippet argument count mismatch";
+                snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements);
+
+                Debug.dump(snippetCopy, "Before specialization");
+
+                if (!replacements.isEmpty()) {
+                    new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy);
+                }
+
+                // Explode all loops in the snippet
+                if (snippetCopy.hasLoops()) {
+                    ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false);
+                    for (Loop loop : cfg.getLoops()) {
+                        LoopBeginNode loopBegin = loop.loopBegin();
+                        SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
+                        Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
+                        int peel = 0;
+                        while (!loopBegin.isDeleted()) {
+                            int mark = snippetCopy.getMark();
+                            LoopTransformUtil.peel(loop, wholeLoop);
+                            Debug.dump(snippetCopy, "After peel %d", peel);
+                            new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy);
+                            peel++;
+                        }
+                        Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
+                    }
+                }
+
+                // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free
+                // of side-effects that prevent deoptimizing to a point before the snippet).
+                for (Node node : snippetCopy.getNodes()) {
+                    if (node instanceof StateSplit) {
+                        StateSplit stateSplit = (StateSplit) node;
+                        FrameState frameState = stateSplit.stateAfter();
+                        assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + frameState.toString(Verbosity.Debugger);
+                        if (frameState != null) {
+                            stateSplit.setStateAfter(null);
+                        }
+                    }
+                }
+
+                new DeadCodeEliminationPhase().apply(snippetCopy);
+                return new SnippetTemplate(args, snippetCopy);
+            }
+        });
+    }
+
+    SnippetTemplate(Object[] args, StructuredGraph graph) {
+        Object[] flattenedArgs = flatten(args);
+        this.graph = graph;
+        this.parameters = new Object[flattenedArgs.length];
+
+        // Find the constant nodes corresponding to the flattened positional parameters
+        for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
+            if (node.kind().isObject()) {
+                CiConstant constant = node.asConstant();
+                if (constant.kind.isObject() && !constant.isNull()) {
+                    for (int i = 0; i < flattenedArgs.length; i++) {
+                        if (flattenedArgs[i] == constant.asObject()) {
+                            parameters[i] = node;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Find the local nodes corresponding to the flattened positional parameters
+        int localIndex = 0;
+        for (int i = 0; i < flattenedArgs.length; i++) {
+            if (flattenedArgs[i] == _) {
+                for (LocalNode local : graph.getNodes(LocalNode.class)) {
+                    if (local.index() == localIndex) {
+                        assert parameters[i] == null;
+                        parameters[i] = local;
+                    }
+                }
+                localIndex++;
+            } else {
+                Object param = parameters[i];
+                if (param == null) {
+                    parameters[i] = flattenedArgs[i];
+                } else {
+                    assert param instanceof ConstantNode;
+                    assert ((ConstantNode) param).kind().isObject();
+                }
+            }
+        }
+
+        nodes = new ArrayList<>(graph.getNodeCount());
+        ReturnNode retNode = null;
+        StartNode entryPointNode = graph.start();
+        for (Node node : graph.getNodes()) {
+            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
+                // Do nothing.
+            } else {
+                nodes.add(node);
+                if (node instanceof ReturnNode) {
+                    retNode = (ReturnNode) node;
+                }
+            }
+        }
+        this.returnNode = retNode;
+    }
+
+    /**
+     * The graph built from the snippet method.
+     */
+    public final StructuredGraph graph;
+
+    /**
+     * The flattened positional parameters of this snippet.
+     * A {@link LocalNode} element is bound to a {@link ValueNode} to be supplied during
+     * instantiation, a {@link ConstantNode} is replaced by an object constant and any
+     * other element denotes an input fixed during specialization.
+     */
+    public final Object[] parameters;
+
+    /**
+     * The return node (if any) of the snippet.
+     */
+    public final ReturnNode returnNode;
+
+    /**
+     * The nodes to be inlined when this specialization is instantiated.
+     */
+    public final ArrayList<Node> nodes;
+
+    private IdentityHashMap<Node, Node> replacements(StructuredGraph replaceeGraph, RiRuntime runtime, Object... args) {
+        Object[] flattenedArgs = flatten(args);
+        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+        assert parameters.length >= flattenedArgs.length;
+        for (int i = 0; i < flattenedArgs.length; i++) {
+            Object param = parameters[i];
+            Object arg = flattenedArgs[i];
+            if (arg == null) {
+                assert !(param instanceof ValueNode) : param;
+            } else if (arg instanceof ValueNode) {
+                assert param instanceof LocalNode;
+                replacements.put((LocalNode) param, (ValueNode) arg);
+            } else {
+                replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph));
+            }
+        }
+        return replacements;
+    }
+
+    /**
+     * Replaces a given node with this specialized snippet.
+     *
+     * @param runtime
+     * @param replacee the node that will be replaced
+     * @param anchor the control flow replacee
+     * @param args the arguments to be bound to the flattened positional parameters of the snippet
+     */
+    public void instantiate(RiRuntime runtime,
+                    Node replacee,
+                    FixedWithNextNode anchor, Object... args) {
+
+        // Inline the snippet nodes, replacing parameters with the given args in the process
+        String name = graph.name == null ? "{copy}" : graph.name + "{copy}";
+        StructuredGraph graphCopy = new StructuredGraph(name, graph.method());
+        StartNode entryPointNode = graph.start();
+        FixedNode firstCFGNode = entryPointNode.next();
+        StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph();
+        IdentityHashMap<Node, Node> replacements = replacements(replaceeGraph, runtime, args);
+        Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
+        Debug.dump(replaceeGraph, "After inlining snippet %s", graphCopy.method());
+
+        // Re-wire the control flow graph around the replacee
+        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+        anchor.replaceAtPredecessors(firstCFGNodeDuplicate);
+        FixedNode next = anchor.next();
+        anchor.setNext(null);
+
+        // Replace all usages of the replacee with the value returned by the snippet
+        Node returnValue = null;
+        if (returnNode != null) {
+            if (returnNode.result() instanceof LocalNode) {
+                returnValue = replacements.get(returnNode.result());
+            } else {
+                returnValue = duplicates.get(returnNode.result());
+            }
+            assert returnValue != null || replacee.usages().isEmpty();
+            replacee.replaceAtUsages(returnValue);
+
+            Node returnDuplicate = duplicates.get(returnNode);
+            returnDuplicate.clearInputs();
+            returnDuplicate.replaceAndDelete(next);
+        }
+
+        // Remove the replacee from its graph
+        replacee.clearInputs();
+        replacee.replaceAtUsages(null);
+        if (replacee instanceof FixedNode) {
+            GraphUtil.killCFG((FixedNode) replacee);
+        } else {
+            replacee.safeDelete();
+        }
+
+        Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this);
+    }
+
+    /**
+     * Flattens a list of objects by replacing any array in {@code args} with its elements.
+     */
+    private static Object[] flatten(Object... args) {
+        List<Object> list = new ArrayList<>(args.length * 2);
+        for (Object o : args) {
+            if (o instanceof Object[]) {
+                list.addAll(Arrays.asList((Object[]) o));
+            } else {
+                list.add(o);
+            }
+        }
+        return list.toArray(new Object[list.size()]);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(graph.toString()).append('(');
+        for (int i = 0; i < parameters.length; i++) {
+            Object param = parameters[i];
+            if (param instanceof ConstantNode) {
+                buf.append(((ConstantNode) param).asConstant().asObject());
+            } else if (param instanceof LocalNode) {
+                buf.append('_');
+            } else {
+                buf.append(param);
+            }
+            if (i != parameters.length - 1) {
+                buf.append(", ");
+            }
+        }
+        return buf.append(')').toString();
+    }
+}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/BoxingEliminationTest.java	Wed May 23 11:55:31 2012 +0200
@@ -22,8 +22,6 @@
  */
 package com.oracle.graal.compiler.tests;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
 import java.util.*;
 
 import org.junit.*;
@@ -32,24 +30,28 @@
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 
 /**
- * In the following tests, the usages of local variable "a" are replaced with the integer constant 0.
- * Then boxing elimination is applied and it is verified that the resulting graph is equal to the
- * graph of the method that just has a "return 1" statement in it.
+ * In the following tests, the usages of local variable "a" are replaced with the integer constant 0. Then boxing
+ * elimination is applied and it is verified that the resulting graph is equal to the graph of the method that just has
+ * a "return 1" statement in it.
  */
 public class BoxingEliminationTest extends GraphTest {
+
     private static final Short s = 2;
-    private static final String REFERENCE_SNIPPET = "referenceSnippet";
 
     @SuppressWarnings("all")
-    public static short referenceSnippet(short a) {
+    public static short referenceSnippet1() {
         return 1;
     }
 
+    @SuppressWarnings("all")
+    public static short referenceSnippet2() {
+        return 2;
+    }
+
     public static Short boxedShort() {
         return 1;
     }
@@ -64,30 +66,31 @@
 
     @Test
     public void test1() {
-        test("test1Snippet");
+        test("test1Snippet", "referenceSnippet1");
     }
 
     @SuppressWarnings("all")
-    public static short test1Snippet(short a) {
+    public static short test1Snippet() {
         return boxedShort();
     }
 
     @Test
     public void test2() {
-        test("test2Snippet");
+        test("test2Snippet", "referenceSnippet1");
     }
 
     @SuppressWarnings("all")
-    public static short test2Snippet(short a) {
+    public static short test2Snippet() {
         return (Short) boxedObject();
     }
+
     @Test
     public void test3() {
-        test("test3Snippet");
+        test("test3Snippet", "referenceSnippet1");
     }
 
     @SuppressWarnings("all")
-    public static short test3Snippet(short a) {
+    public static short test3Snippet() {
         short b = boxedShort();
         if (b < 0) {
             b = boxedShort();
@@ -97,15 +100,15 @@
 
     @Test
     public void test4() {
-        test("test4Snippet");
+        test("test4Snippet", "referenceSnippet2");
     }
 
     @SuppressWarnings("all")
-    public static short test4Snippet(short a) {
+    public static short test4Snippet() {
         return constantBoxedShort();
     }
 
-    private void test(final String snippet) {
+    private void test(final String snippet, final String referenceSnippet) {
         Debug.scope("BoxingEliminationTest", new DebugDumpScope(snippet), new Runnable() {
             @Override
             public void run() {
@@ -115,11 +118,6 @@
                 PhasePlan phasePlan = getDefaultPhasePlan();
                 phasePlan.addPhase(PhasePosition.AFTER_PARSING, identifyBoxingPhase);
                 identifyBoxingPhase.apply(graph);
-                LocalNode local = graph.getNodes(LocalNode.class).iterator().next();
-                ConstantNode constant = ConstantNode.forShort((short) 0, graph);
-                for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) {
-                    n.replaceFirstInput(local, constant);
-                }
                 Collection<Invoke> hints = new ArrayList<>();
                 for (Invoke invoke : graph.getInvokes()) {
                     hints.add(invoke);
@@ -133,7 +131,7 @@
                 new ExpandBoxingNodesPhase(pool).apply(graph);
                 new CanonicalizerPhase(null, runtime(), null).apply(graph);
                 new DeadCodeEliminationPhase().apply(graph);
-                StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
+                StructuredGraph referenceGraph = parse(referenceSnippet);
                 assertEquals(referenceGraph, graph);
             }
         });
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompareCanonicalizerTest.java	Wed May 23 11:55:31 2012 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.tests;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.nodes.*;
+
+public class CompareCanonicalizerTest extends GraphTest {
+
+    @Test
+    public void testCanonicalComparison() {
+        StructuredGraph referenceGraph = parse("referenceCanonicalComparison");
+        for (int i = 1; i < 4; i++) {
+            StructuredGraph graph = parse("canonicalCompare" + i);
+            assertEquals(referenceGraph, graph);
+        }
+        new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph);
+        for (int i = 1; i < 4; i++) {
+            StructuredGraph graph = parse("canonicalCompare" + i);
+            new CanonicalizerPhase(null, runtime(), null).apply(graph);
+            assertEquals(referenceGraph, graph);
+        }
+    }
+
+    public static int referenceCanonicalComparison(int a, int b) {
+        if (a < b) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int canonicalCompare1(int a, int b) {
+        if (a >= b) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+
+    public static int canonicalCompare2(int a, int b) {
+        if (b > a) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    public static int canonicalCompare3(int a, int b) {
+        if (b <= a) {
+            return 2;
+        } else {
+            return 1;
+        }
+    }
+}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ConditionTest.java	Wed May 23 11:55:31 2012 +0200
@@ -41,7 +41,7 @@
             for (Condition c2 : Condition.values()) {
                 boolean implies = c1.implies(c2);
                 if (implies) {
-                    for (int i = 0; i < 10000; i++) {
+                    for (int i = 0; i < 1000; i++) {
                         CiConstant a = CiConstant.forInt(rand.nextInt());
                         CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
                         boolean result1 = c1.foldCondition(a, b, null, false);
@@ -63,7 +63,7 @@
                 Condition join = c1.join(c2);
                 assertTrue(join == c2.join(c1));
                 if (join != null) {
-                    for (int i = 0; i < 10000; i++) {
+                    for (int i = 0; i < 1000; i++) {
                         CiConstant a = CiConstant.forInt(rand.nextInt());
                         CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
                         boolean result1 = c1.foldCondition(a, b, null, false);
@@ -86,7 +86,7 @@
                 Condition meet = c1.meet(c2);
                 assertTrue(meet == c2.meet(c1));
                 if (meet != null) {
-                    for (int i = 0; i < 10000; i++) {
+                    for (int i = 0; i < 1000; i++) {
                         CiConstant a = CiConstant.forInt(rand.nextInt());
                         CiConstant b = CiConstant.forInt(i < 100 ? a.asInt() : rand.nextInt());
                         boolean result1 = c1.foldCondition(a, b, null, false);
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/DegeneratedLoopsTest.java	Wed May 23 11:55:31 2012 +0200
@@ -22,13 +22,10 @@
  */
 package com.oracle.graal.compiler.tests;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
 import org.junit.*;
 
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -42,7 +39,7 @@
 
     @SuppressWarnings("all")
     public static int referenceSnippet(int a) {
-        return 1;
+        return a;
     }
 
     @Test
@@ -79,16 +76,12 @@
     private void test(String snippet) {
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
-        LocalNode local = graph.getNodes(LocalNode.class).iterator().next();
-        ConstantNode constant = ConstantNode.forInt(0, graph);
-        for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) {
-            n.replaceFirstInput(local, constant);
-        }
         for (Invoke invoke : graph.getInvokes()) {
             invoke.intrinsify(null);
         }
         new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET); Debug.dump(referenceGraph, "Graph");
+        StructuredGraph referenceGraph = parse(REFERENCE_SNIPPET);
+        Debug.dump(referenceGraph, "Graph");
         assertEquals(referenceGraph, graph);
     }
 }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Wed May 23 11:55:31 2012 +0200
@@ -30,9 +30,13 @@
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.phases.PhasePlan.PhasePosition;
+import com.oracle.graal.compiler.schedule.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
 import com.oracle.graal.java.*;
+import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
@@ -65,13 +69,55 @@
     }
 
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
+        String expectedString = getCanonicalGraphString(expected);
+        String actualString = getCanonicalGraphString(graph);
+        String mismatchString = "mismatch in graphs:\n========= expected =========\n" + expectedString + "\n\n========= actual =========\n" + actualString;
+
         if (expected.getNodeCount() != graph.getNodeCount()) {
             Debug.dump(expected, "Node count not matching - expected");
             Debug.dump(graph, "Node count not matching - actual");
-            Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
+            Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString);
+        }
+        if (!expectedString.equals(actualString)) {
+            Debug.dump(expected, "mismatching graphs - expected");
+            Debug.dump(graph, "mismatching graphs - actual");
+            Assert.fail(mismatchString);
         }
     }
 
+    private static String getCanonicalGraphString(StructuredGraph graph) {
+        SchedulePhase schedule = new SchedulePhase();
+        schedule.apply(graph);
+
+        NodeMap<Integer> canonicalId = graph.createNodeMap();
+        int nextId = 0;
+
+        StringBuilder result = new StringBuilder();
+        for (Block block : schedule.getCFG().getBlocks()) {
+            result.append("Block " + block + " ");
+            if (block == schedule.getCFG().getStartBlock()) {
+                result.append("* ");
+            }
+            result.append("-> ");
+            for (Block succ : block.getSuccessors()) {
+                result.append(succ + " ");
+            }
+            result.append("\n");
+            for (Node node : schedule.getBlockToNodesMap().get(block)) {
+                int id;
+                if (canonicalId.get(node) != null) {
+                    id = canonicalId.get(node);
+                } else {
+                    id = nextId++;
+                    canonicalId.set(node, id);
+                }
+                String name = node instanceof ConstantNode ? node.toString(Verbosity.Name) : node.getClass().getSimpleName();
+                result.append("  " + id + "|" + name + "    (" + node.usages().size() + ")\n");
+            }
+        }
+        return result.toString();
+    }
+
     protected GraalRuntime runtime() {
         return runtime;
     }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfCanonicalizerTest.java	Wed May 23 10:09:39 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.compiler.tests;
-
-import org.junit.*;
-
-import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
-
-public class InstanceOfCanonicalizerTest extends GraphTest {
-
-    /**
-     * The problem tested here is the following: When canonicalizing a negated instanceof for which the exact type
-     * suggests that the instanceof is true, we still need to check if the value is null. (because this would make the
-     * instanceof false, and thus the negated instanceof true).
-     *
-     * This test case is constructed by replacing an instanceof with its negated counterpart, since negated instanceof
-     * operations will only be created in complicated cases.
-     */
-    @Test
-    public void test1() {
-        StructuredGraph graph = parse("testSnippet1");
-        Debug.dump(graph, "Graph");
-        for (Node node : graph.getNodes().snapshot()) {
-            if (node instanceof InstanceOfNode) {
-                graph.replaceFloating((InstanceOfNode) node, ((InstanceOfNode) node).negate());
-            }
-        }
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        Debug.dump(graph, "Graph");
-        for (Node node : graph.getNodes()) {
-            if (node instanceof InstanceOfNode) {
-                Assert.fail("InstanceOfNode should have been canonicalized");
-            } else if (node instanceof ReturnNode) {
-                ReturnNode ret = (ReturnNode) node;
-                Assert.assertTrue("return value should be a MaterializeNode " + ret.result(), ret.result() instanceof MaterializeNode);
-                MaterializeNode materialize = (MaterializeNode) ret.result();
-                Assert.assertTrue("return value should depend on nullness of parameter " + materialize.condition(), materialize.condition() instanceof NullCheckNode);
-            }
-
-        }
-    }
-
-    @SuppressWarnings("all")
-    public static boolean testSnippet1(String s) {
-        return s instanceof String;
-    }
-}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InvokeTest.java	Wed May 23 11:55:31 2012 +0200
@@ -22,15 +22,12 @@
  */
 package com.oracle.graal.compiler.tests;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
 import java.util.*;
 
 import org.junit.*;
 
 import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
 /**
@@ -42,13 +39,17 @@
 
     private static final String REFERENCE_SNIPPET = "referenceSnippet";
 
-    @SuppressWarnings("all")
-    public static int referenceSnippet(int a) {
+    public static int const1() {
         return 1;
     }
 
-    public static int const1() {
-        return 1;
+    public static int const7() {
+        return 7;
+    }
+
+    @SuppressWarnings("all")
+    public static int referenceSnippet() {
+        return 7;
     }
 
     @Test
@@ -57,8 +58,8 @@
     }
 
     @SuppressWarnings("all")
-    public static int test1Snippet(int a) {
-        return const1();
+    public static int test1Snippet() {
+        return const7();
     }
 
     @Test
@@ -67,17 +68,12 @@
     }
 
     @SuppressWarnings("all")
-    public static int test2Snippet(int a) {
+    public static int test2Snippet() {
         return const1() + const1() + const1() + const1() + const1() + const1() + const1();
     }
 
     private void test(String snippet) {
         StructuredGraph graph = parse(snippet);
-        LocalNode local = graph.getNodes(LocalNode.class).iterator().next();
-        ConstantNode constant = ConstantNode.forInt(0, graph);
-        for (Node n : local.usages().filter(isNotA(FrameState.class)).snapshot()) {
-            n.replaceFirstInput(local, constant);
-        }
         Collection<Invoke> hints = new ArrayList<>();
         for (Invoke invoke : graph.getInvokes()) {
             hints.add(invoke);
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java	Wed May 23 11:55:31 2012 +0200
@@ -27,7 +27,6 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.compiler.types.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 
@@ -44,7 +43,7 @@
         }
     }
 
-    @Test
+    @Test(expected = AssertionFailedError.class)
     public void test1() {
         test("test1Snippet", "referenceSnippet1");
     }
@@ -61,7 +60,7 @@
         }
     }
 
-    @Test
+    @Test(expected = AssertionFailedError.class)
     public void test2() {
         test("test2Snippet", "referenceSnippet1");
     }
@@ -78,7 +77,7 @@
         }
     }
 
-    @Test
+    @Test(expected = AssertionFailedError.class)
     public void test3() {
         test("test3Snippet", "referenceSnippet2");
     }
@@ -163,12 +162,12 @@
     }
 
     private void test(String snippet, String referenceSnippet) {
-
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
-        System.out.println("==================== " + snippet);
+//        TypeSystemTest.outputGraph(graph);
         new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new PropagateTypeCachePhase(null, null, null).apply(graph);
+        new CheckCastEliminationPhase().apply(graph);
+        new CanonicalizerPhase(null, runtime(), null).apply(graph);
         StructuredGraph referenceGraph = parse(referenceSnippet);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java	Wed May 23 11:55:31 2012 +0200
@@ -26,7 +26,7 @@
 
 import junit.framework.Assert;
 
-import org.junit.*;
+import org.junit.Test;
 
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.schedule.*;
@@ -36,7 +36,6 @@
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.printer.*;
 
 /**
  * In the following tests, the scalar type system of the compiler should be complete enough to see the relation between the different conditions.
@@ -184,31 +183,33 @@
         return ((InputStream) o).available();
     }
 
+    @SuppressWarnings("unused")
     private void test(String snippet, String referenceSnippet) {
-
-        StructuredGraph graph = parse(snippet);
-        Debug.dump(graph, "Graph");
-        System.out.println("==================== " + snippet);
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new PropagateTypeCachePhase(null, runtime(), null).apply(graph);
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new GlobalValueNumberingPhase().apply(graph);
-        StructuredGraph referenceGraph = parse(referenceSnippet);
-        new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph);
-        new GlobalValueNumberingPhase().apply(referenceGraph);
-        assertEquals(referenceGraph, graph);
+        // TODO(ls) temporarily disabled, reintroduce when a proper type system is available
+        if (false) {
+            StructuredGraph graph = parse(snippet);
+            Debug.dump(graph, "Graph");
+            new CanonicalizerPhase(null, runtime(), null).apply(graph);
+            new PropagateTypeCachePhase(null, runtime(), null).apply(graph);
+            new CanonicalizerPhase(null, runtime(), null).apply(graph);
+            new GlobalValueNumberingPhase().apply(graph);
+            StructuredGraph referenceGraph = parse(referenceSnippet);
+            new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph);
+            new GlobalValueNumberingPhase().apply(referenceGraph);
+            assertEquals(referenceGraph, graph);
+        }
     }
 
     @Override
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
         if (expected.getNodeCount() != graph.getNodeCount()) {
-            Debug.dump(expected, "Node count not matching - expected");
-            Debug.dump(graph, "Node count not matching - actual");
-            System.out.println("================ expected");
-            outputGraph(expected);
-            System.out.println("================ actual");
-            outputGraph(graph);
-            new IdealGraphPrinterDumpHandler().dump(graph, "asdf");
+//            Debug.dump(expected, "Node count not matching - expected");
+//            Debug.dump(graph, "Node count not matching - actual");
+//            System.out.println("================ expected");
+//            outputGraph(expected);
+//            System.out.println("================ actual");
+//            outputGraph(graph);
+//            new IdealGraphPrinterDumpHandler().dump(graph, "asdf");
             Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
         }
     }
@@ -232,16 +233,17 @@
         }
     }
 
-
+    @SuppressWarnings("unused")
     private <T extends Node & Node.IterableNodeType> void test(String snippet, Class<T> clazz) {
-        StructuredGraph graph = parse(snippet);
-        Debug.dump(graph, "Graph");
-        new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new PropagateTypeCachePhase(null, runtime(), null).apply(graph);
-        Debug.dump(graph, "Graph");
-        if (graph.getNodes(clazz).iterator().hasNext()) {
-            outputGraph(graph);
+        // TODO(ls) temporarily disabled, reintroduce when a proper type system is available
+        if (false) {
+            StructuredGraph graph = parse(snippet);
+            Debug.dump(graph, "Graph");
+            new CanonicalizerPhase(null, runtime(), null).apply(graph);
+            new PropagateTypeCachePhase(null, runtime(), null).apply(graph);
+            new CanonicalizerPhase(null, runtime(), null).apply(graph);
+            Debug.dump(graph, "Graph");
+            Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext());
         }
-        Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext());
     }
 }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java	Wed May 23 10:09:39 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java	Wed May 23 11:55:31 2012 +0200
@@ -473,6 +473,8 @@
      */
     public static CiConstant forBoxed(CiKind kind, Object value) {
         switch (kind) {
+            case Boolean:
+                return forBoolean((Boolean) value);
             case Byte:
                 return forByte((Byte) value);
             case Char: