changeset 5392:3f9895797ff4

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 11 May 2012 16:02:24 +0200
parents 5097f21f6c2b (diff) 8be0c73cf118 (current diff)
children 9b44497fef98 afb983c25aa0
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java
diffstat 25 files changed, 628 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 11 16:02:24 2012 +0200
@@ -136,10 +136,15 @@
             new InliningPhase(target, runtime, null, assumptions, cache, plan, optimisticOpts).apply(graph);
             new DeadCodeEliminationPhase().apply(graph);
             new PhiStampPhase().apply(graph);
+
             if (GraalOptions.PropagateTypes) {
                 new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
             }
 
+            if (GraalOptions.CheckCastElimination) {
+                new CheckCastEliminationPhase().apply(graph);
+            }
+
             if (GraalOptions.OptCanonicalizer) {
                 new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
             }
@@ -172,6 +177,9 @@
         new LoweringPhase(runtime, assumptions).apply(graph);
         new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph);
 
+        if (GraalOptions.CullFrameStates) {
+            new CullFrameStatesPhase().apply(graph);
+        }
         if (GraalOptions.Lower) {
             new FloatingReadPhase().apply(graph);
             if (GraalOptions.OptGVN) {
@@ -185,6 +193,11 @@
         if (GraalOptions.PropagateTypes) {
             new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
         }
+
+        if (GraalOptions.CheckCastElimination) {
+            new CheckCastEliminationPhase().apply(graph);
+        }
+
         if (GraalOptions.OptCanonicalizer) {
             new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri May 11 16:02:24 2012 +0200
@@ -164,6 +164,8 @@
 
     // Code generator settings
     public static boolean PropagateTypes                     = ____;
+    public static boolean CheckCastElimination               = true;
+    public static boolean CullFrameStates                    = ____;
     public static boolean UseProfilingInformation            = true;
            static boolean RemoveNeverExecutedCode            = true;
            static boolean UseExceptionProbability            = true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java	Fri May 11 16:02:24 2012 +0200
@@ -0,0 +1,331 @@
+/*
+ * 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.phases;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.compiler.graph.*;
+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.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.max.cri.ri.*;
+
+public class CheckCastEliminationPhase extends Phase {
+
+    private static final DebugMetric metricInstanceOfRegistered = Debug.metric("InstanceOfRegistered");
+    private static final DebugMetric metricIsTypeRegistered = Debug.metric("IsTypeRegistered");
+    private static final DebugMetric metricNullCheckRegistered = Debug.metric("NullCheckRegistered");
+    private static final DebugMetric metricCheckCastRemoved = Debug.metric("CheckCastRemoved");
+    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 StructuredGraph graph;
+
+    static PrintStream out = System.out;
+
+    @Override
+    protected void run(StructuredGraph inputGraph) {
+        graph = inputGraph;
+//        if (!graph.method().holder().name().contains("DiskIndex")) {
+//            return;
+//        }
+//        if (!graph.method().name().equals("writeCategoryTable")) {
+//            return;
+//        }
+//        out.println("checkcast " + graph.method());
+
+        new EliminateCheckCasts(graph.start(), new State()).apply();
+    }
+
+    public static class State implements MergeableState<State> {
+
+        private IdentityHashMap<ValueNode, RiResolvedType> knownTypes;
+        private HashSet<ValueNode> knownNotNull;
+        private HashSet<ValueNode> knownNull;
+
+        public State() {
+            this.knownTypes = new IdentityHashMap<>();
+            this.knownNotNull = new HashSet<>();
+            this.knownNull = new HashSet<>();
+        }
+
+        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);
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<State> withStates) {
+            IdentityHashMap<ValueNode, RiResolvedType> newKnownTypes = new IdentityHashMap<>();
+            HashSet<ValueNode> newKnownNotNull = new HashSet<>();
+            HashSet<ValueNode> newKnownNull = new HashSet<>();
+
+            for (Map.Entry<ValueNode, RiResolvedType> entry : knownTypes.entrySet()) {
+                ValueNode node = entry.getKey();
+                RiResolvedType type = entry.getValue();
+
+                for (State other : withStates) {
+                    RiResolvedType otherType = other.getNodeType(node);
+                    type = widen(type, otherType);
+                    if (type == null) {
+                        break;
+                    }
+                }
+                if (type == null && type != node.declaredType()) {
+                    newKnownTypes.put(node, type);
+                }
+            }
+            for (ValueNode node : knownNotNull) {
+                boolean notNull = true;
+                for (State other : withStates) {
+                    if (!other.knownNotNull.contains(node)) {
+                        notNull = false;
+                        break;
+                    }
+                }
+                if (notNull) {
+                    newKnownNotNull.add(node);
+                }
+            }
+            for (ValueNode node : knownNull) {
+                boolean nul = true;
+                for (State other : withStates) {
+                    if (!other.knownNull.contains(node)) {
+                        nul = false;
+                        break;
+                    }
+                }
+                if (nul) {
+                    newKnownNull.add(node);
+                }
+            }
+            /*
+            // this piece of code handles phis (merges the types and knownNull/knownNotNull of the values)
+            if (!(merge instanceof LoopBeginNode)) {
+                for (PhiNode phi : merge.phis()) {
+                    if (phi.type() == PhiType.Value && phi.kind() == CiKind.Object) {
+                        ValueNode firstValue = phi.valueAt(0);
+                        RiResolvedType type = getNodeType(firstValue);
+                        boolean notNull = knownNotNull.contains(firstValue);
+                        boolean nul = knownNull.contains(firstValue);
+
+                        for (int i = 0; i < withStates.size(); i++) {
+                            State otherState = withStates.get(i);
+                            ValueNode value = phi.valueAt(i + 1);
+                            RiResolvedType otherType = otherState.getNodeType(value);
+                            type = widen(type, otherType);
+                            notNull &= otherState.knownNotNull.contains(value);
+                            nul &= otherState.knownNull.contains(value);
+                        }
+                        if (type == null && type != phi.declaredType()) {
+                            newKnownTypes.put(phi, type);
+                        }
+                        if (notNull) {
+                            newKnownNotNull.add(phi);
+                        }
+                        if (nul) {
+                            newKnownNull.add(phi);
+                        }
+                    }
+                }
+            }
+            */
+            this.knownTypes = newKnownTypes;
+            this.knownNotNull = newKnownNotNull;
+            this.knownNull = newKnownNull;
+            return true;
+        }
+
+        public RiResolvedType getNodeType(ValueNode node) {
+            RiResolvedType result = knownTypes.get(node);
+            return result == null ? node.declaredType() : result;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) {
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+        }
+
+        @Override
+        public State clone() {
+            return new State(knownTypes, knownNotNull, knownNull);
+        }
+    }
+
+    public static RiResolvedType widen(RiResolvedType a, RiResolvedType b) {
+        if (a == null || b == null) {
+            return null;
+        } else if (a == b) {
+            return a;
+        } else {
+            return a.leastCommonAncestor(b);
+        }
+    }
+
+    public static RiResolvedType tighten(RiResolvedType a, RiResolvedType b) {
+        if (a == null) {
+            return b;
+        } else if (b == null) {
+            return a;
+        } else if (a == b) {
+            return a;
+        } else if (a.isSubtypeOf(b)) {
+            return a;
+        } else if (b.isSubtypeOf(a)) {
+            return b;
+        } else {
+            return a;
+        }
+    }
+
+    public class EliminateCheckCasts extends PostOrderNodeIterator<State> {
+        private BeginNode lastBegin = null;
+
+        public EliminateCheckCasts(FixedNode start, State initialState) {
+            super(start, initialState);
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            if (node instanceof BeginNode) {
+                BeginNode begin = (BeginNode) node;
+                lastBegin = begin;
+                Node pred = node.predecessor();
+                if (pred != null && pred instanceof IfNode) {
+                    IfNode ifNode = (IfNode) pred;
+                    if (ifNode.compare() instanceof InstanceOfNode) {
+                        InstanceOfNode instanceOf = (InstanceOfNode) ifNode.compare();
+                        if ((node == ifNode.trueSuccessor()) != instanceOf.negated()) {
+                            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) {
+                            state.knownNotNull.add(nullCheck.object());
+                        } else {
+                            state.knownNull.add(nullCheck.object());
+                        }
+                        metricNullCheckRegistered.increment();
+                    } else if (ifNode.compare() instanceof IsTypeNode) {
+                        IsTypeNode isType = (IsTypeNode) ifNode.compare();
+                        if (isType.objectClass() instanceof ReadHubNode && (node == ifNode.trueSuccessor())) {
+                            ReadHubNode readHub = (ReadHubNode) isType.objectClass();
+                            ValueNode object = readHub.object();
+                            state.knownNotNull.add(object);
+                            state.knownTypes.put(object, tighten(isType.type(), state.getNodeType(object)));
+                            metricIsTypeRegistered.increment();
+                        }
+                    }
+                }
+                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;
+                        }
+                        if (removeCheck) {
+                            metricNullCheckGuardRemoved.increment();
+                        }
+                    }
+                    if (removeCheck) {
+                        guard.replaceAtUsages(begin);
+                        GraphUtil.killWithUnusedFloatingInputs(guard);
+                    }
+                }
+            } else if (node instanceof CheckCastNode) {
+                CheckCastNode checkCast = (CheckCastNode) node;
+                RiResolvedType type = state.getNodeType(checkCast.object());
+                if (checkCast.targetClass() != null && type != null && type.isSubtypeOf(checkCast.targetClass())) {
+                    PiNode piNode;
+                    if (state.knownNotNull.contains(checkCast.object())) {
+                        piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, StampFactory.declaredNonNull(type)));
+                    } else {
+                        piNode = graph.unique(new PiNode(checkCast.object(), lastBegin, StampFactory.declared(type)));
+                    }
+                    checkCast.replaceAtUsages(piNode);
+                    graph.removeFixed(checkCast);
+                    metricCheckCastRemoved.increment();
+                }
+            } else if (node instanceof IfNode) {
+                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 (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) {
+                    ifNode.setCompare(replaceWith);
+                    if (compare.usages().isEmpty()) {
+                        GraphUtil.killWithUnusedFloatingInputs(compare);
+                    }
+                }
+            }
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CullFrameStatesPhase.java	Fri May 11 16:02:24 2012 +0200
@@ -0,0 +1,115 @@
+/*
+ * 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.phases;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.graph.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * This phase culls unused FrameStates from the graph.
+ * It does a post order iteration over the graph, and
+ */
+public class CullFrameStatesPhase extends Phase {
+
+    private static final DebugMetric metricFrameStatesCulled = Debug.metric("FrameStatesCulled");
+    private static final DebugMetric metricMergesTraversed = Debug.metric("MergesTraversed");
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        new CullFrameStates(graph.start(), new State(null)).apply();
+    }
+
+    public static class State implements MergeableState<State> {
+
+        private FrameState lastFrameState;
+
+        public State(FrameState lastFrameState) {
+            this.lastFrameState = lastFrameState;
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<State> withStates) {
+            FrameState stateAfter = merge.stateAfter();
+            if (merge instanceof LoopBeginNode) {
+                if (stateAfter != null) {
+                    lastFrameState = stateAfter;
+                }
+                return true;
+            }
+            metricMergesTraversed.increment();
+            if (stateAfter != null) {
+                for (State other : withStates) {
+                    if (other.lastFrameState != lastFrameState) {
+                        lastFrameState = stateAfter;
+                        return true;
+                    }
+                }
+                metricFrameStatesCulled.increment();
+                merge.setStateAfter(null);
+                if (stateAfter.usages().isEmpty()) {
+                    GraphUtil.killWithUnusedFloatingInputs(stateAfter);
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<State> loopEndStates) {
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+        }
+
+        @Override
+        public State clone() {
+            return new State(lastFrameState);
+        }
+    }
+
+    public static class CullFrameStates extends PostOrderNodeIterator<State> {
+
+        public CullFrameStates(FixedNode start, State initialState) {
+            super(start, initialState);
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            if (node instanceof StateSplit) {
+                FrameState stateAfter = ((StateSplit) node).stateAfter();
+                if (stateAfter != null) {
+                    state.lastFrameState = stateAfter;
+                }
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java	Fri May 11 16:02:24 2012 +0200
@@ -145,9 +145,9 @@
             Debug.log("Register read to node %s.", readNode);
             FloatingReadNode floatingRead;
             if (readNode.location().locationIdentity() == LocationNode.FINAL_LOCATION) {
-                floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.guard(), readNode.location(), readNode.stamp()));
+                floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), null, readNode.stamp(), readNode.dependencies()));
             } else {
-                floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.guard(), readNode.location(), readNode.stamp(), getLocationForRead(readNode)));
+                floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), getLocationForRead(readNode), readNode.stamp(), readNode.dependencies()));
             }
             graph.replaceFixedWithFloating(readNode, floatingRead);
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java	Fri May 11 16:02:24 2012 +0200
@@ -208,6 +208,9 @@
                 if (GraalOptions.Intrinsify) {
                     new IntrinsificationPhase(runtime).apply(newGraph);
                 }
+                if (GraalOptions.CullFrameStates) {
+                    new CullFrameStatesPhase().apply(newGraph);
+                }
                 if (GraalOptions.CacheGraphs && cache != null) {
                     cache.put(newGraph);
                 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java	Fri May 11 16:02:24 2012 +0200
@@ -32,9 +32,8 @@
     @Override
     protected void run(StructuredGraph graph) {
         for (FloatingReadNode n : graph.getNodes(FloatingReadNode.class)) {
-            if (n.dependencies().size() > 0) {
-                assert n.dependencies().size() == 1;
-                Node memoryInput = n.dependencies().get(0);
+            if (n.lastLocationAccess() != null) {
+                Node memoryInput = n.lastLocationAccess();
                 if (memoryInput instanceof WriteNode) {
                     WriteNode other = (WriteNode) memoryInput;
                     if (other.object() == n.object() && other.location() == n.location()) {
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValue.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValue.java	Fri May 11 16:02:24 2012 +0200
@@ -22,8 +22,24 @@
  */
 package com.oracle.graal.debug.internal;
 
+import java.util.*;
+
 public abstract class DebugValue {
 
+    public static final Comparator<DebugValue> ORDER_BY_NAME = new Comparator<DebugValue>() {
+        @Override
+        public int compare(DebugValue o1, DebugValue o2) {
+            // this keeps the "Runs" metric at the top of the list
+            if (o1.getName().equals("Runs")) {
+                return o2.getName().equals("Runs") ? 0 : -1;
+            }
+            if (o2.getName().equals("Runs")) {
+                return o1.getName().equals("Runs") ? 0 : 1;
+            }
+            return o1.getName().compareTo(o2.getName());
+        }
+    };
+
     private String name;
     private int index;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 11 16:02:24 2012 +0200
@@ -255,14 +255,17 @@
             List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
             List<DebugValue> debugValues = KeyRegistry.getDebugValues();
             if (debugValues.size() > 0) {
+                ArrayList<DebugValue> sortedValues = new ArrayList<>(debugValues);
+                Collections.sort(sortedValues, DebugValue.ORDER_BY_NAME);
+
                 if (GraalOptions.SummarizeDebugValues) {
-                    printSummary(topLevelMaps, debugValues);
+                    printSummary(topLevelMaps, sortedValues);
                 } else if (GraalOptions.PerThreadDebugValues) {
                     for (DebugValueMap map : topLevelMaps) {
                         TTY.println("Showing the results for thread: " + map.getName());
                         map.group();
                         map.normalize();
-                        printMap(map, debugValues, 0);
+                        printMap(map, sortedValues, 0);
                     }
                 } else {
                     DebugValueMap globalMap = new DebugValueMap("Global");
@@ -279,7 +282,7 @@
                         globalMap.group();
                     }
                     globalMap.normalize();
-                    printMap(globalMap, debugValues, 0);
+                    printMap(globalMap, sortedValues, 0);
                 }
             }
         }
@@ -326,6 +329,7 @@
 
         printIndent(level);
         TTY.println("%s", map.getName());
+
         for (DebugValue value : debugValues) {
             long l = map.getCurrentValue(value.getIndex());
             if (l != 0) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri May 11 16:02:24 2012 +0200
@@ -290,7 +290,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.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, field.leafGraphId()));
+            memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(field.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, field.leafGraphId()));
             graph.replaceFixedWithFixed(field, memoryRead);
             if (field.isVolatile()) {
                 MembarNode preMembar = graph.add(new MembarNode(JMM_PRE_VOLATILE_READ));
@@ -302,7 +302,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.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, storeField.leafGraphId()));
+            memoryWrite.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(storeField.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, storeField.leafGraphId()));
             memoryWrite.setStateAfter(storeField.stateAfter());
             graph.replaceFixedWithFixed(storeField, memoryWrite);
 
@@ -336,16 +336,16 @@
             }
         } else if (n instanceof LoadIndexedNode) {
             LoadIndexedNode loadIndexed = (LoadIndexedNode) n;
-            GuardNode boundsCheck = createBoundsCheck(loadIndexed, tool, loadIndexed.leafGraphId());
+            Node boundsCheck = createBoundsCheck(loadIndexed, tool, loadIndexed.leafGraphId());
 
             CiKind elementKind = loadIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, loadIndexed.index());
             ReadNode memoryRead = graph.add(new ReadNode(loadIndexed.array(), arrayLocation, loadIndexed.stamp()));
-            memoryRead.setGuard(boundsCheck);
+            memoryRead.dependencies().add(boundsCheck);
             graph.replaceFixedWithFixed(loadIndexed, memoryRead);
         } else if (n instanceof StoreIndexedNode) {
             StoreIndexedNode storeIndexed = (StoreIndexedNode) n;
-            GuardNode boundsCheck = createBoundsCheck(storeIndexed, tool, storeIndexed.leafGraphId());
+            Node boundsCheck = createBoundsCheck(storeIndexed, tool, storeIndexed.leafGraphId());
 
             CiKind elementKind = storeIndexed.elementKind();
             LocationNode arrayLocation = createArrayLocation(graph, elementKind, storeIndexed.index());
@@ -365,17 +365,17 @@
                         assert elementType.name().equals("Ljava/lang/Object;") : elementType.name();
                     }
                 } else {
-                    GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID);
-                    FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull()));
-                    arrayClass.setGuard(guard);
-                    FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull()));
+                    Node guard = tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, 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()));
                     checkcast = graph.add(new CheckCastNode(arrayElementKlass, null, value));
                     graph.addBeforeFixed(storeIndexed, checkcast);
                     value = checkcast;
                 }
             }
             WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation));
-            memoryWrite.setGuard(boundsCheck);
+            memoryWrite.dependencies().add(boundsCheck);
             memoryWrite.setStateAfter(storeIndexed.stateAfter());
 
             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
@@ -392,7 +392,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.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
+            memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(load.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixedWithFixed(load, memoryRead);
         } else if (n instanceof UnsafeStoreNode) {
             UnsafeStoreNode store = (UnsafeStoreNode) n;
@@ -409,7 +409,7 @@
             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.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
+            memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
             if (GraalOptions.HIRLowerCheckcast != null && graph.method() != null && graph.method().holder().name().contains(GraalOptions.HIRLowerCheckcast)) {
@@ -445,8 +445,8 @@
         return IndexedLocationNode.create(LocationNode.getArrayLocation(elementKind), elementKind, config.getArrayOffset(elementKind), index, graph);
     }
 
-    private static GuardNode createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool, long leafGraphId) {
-        return (GuardNode) tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length())), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId);
+    private static Node createBoundsCheck(AccessIndexedNode n, CiLoweringTool tool, long leafGraphId) {
+        return tool.createGuard(n.graph().unique(new CompareNode(n.index(), Condition.BT, n.length())), RiDeoptReason.BoundsCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId);
     }
 
     @Override
@@ -467,7 +467,7 @@
                 StructuredGraph graph = new StructuredGraph();
                 LocalNode receiver = graph.unique(new LocalNode(CiKind.Object, 0));
                 SafeReadNode klassOop = safeReadHub(graph, receiver, StructuredGraph.INVALID_GRAPH_ID);
-                FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.classMirrorOffset, graph), StampFactory.objectNonNull()));
+                FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.classMirrorOffset, graph), null, StampFactory.objectNonNull()));
                 ReturnNode ret = graph.add(new ReturnNode(result));
                 graph.start().setNext(klassOop);
                 klassOop.setNext(ret);
@@ -480,7 +480,7 @@
                 SafeReadNode klassOop = safeRead(graph, CiKind.Object, receiver, config.klassOopOffset, StampFactory.objectNonNull(), StructuredGraph.INVALID_GRAPH_ID);
                 graph.start().setNext(klassOop);
                 // TODO(thomaswue): Care about primitive classes! Crashes for primitive classes at the moment (klassOop == null)
-                FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), StampFactory.forKind(CiKind.Int)));
+                FloatingReadNode result = graph.unique(new FloatingReadNode(klassOop, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Int, config.klassModifierFlagsOffset, graph), null, StampFactory.forKind(CiKind.Int)));
                 ReturnNode ret = graph.add(new ReturnNode(result));
                 klassOop.setNext(ret);
                 return graph;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AnchorNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AnchorNode.java	Fri May 11 16:02:24 2012 +0200
@@ -22,28 +22,22 @@
  */
 package com.oracle.graal.nodes;
 
-import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * The {@code AnchorNode} can be used a lower bound for a Guard. It can also be used as an upper bound if no other FixedNode can be used for that purpose.
+ * The {@code AnchorNode} can be used a lower bound for a guard. It can also be used as an upper bound if no other FixedNode can be used for that purpose.
+ * The guards that should be kept above this node need to be added to the {@link #dependencies()} collection.
  */
 public final class AnchorNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable {
 
-    @Input(notDataflow = true) private final NodeInputList<GuardNode> guards = new NodeInputList<>(this);
-
     public AnchorNode() {
         super(StampFactory.illegal());
     }
 
-    public void addGuard(GuardNode x) {
-        guards.add(x);
-    }
-
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (this.usages().size() == 0 && guards.size() == 0) {
+        if (this.usages().size() == 0 && dependencies().isEmpty()) {
             return null;
         }
         return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Fri May 11 16:02:24 2012 +0200
@@ -84,7 +84,7 @@
     public void lower(CiLoweringTool tool) {
         AnchorNode newAnchor = graph().add(new AnchorNode());
         for (BooleanNode b : conditions) {
-            newAnchor.addGuard((GuardNode) tool.createGuard(b, deoptReason, action, leafGraphId));
+            newAnchor.dependencies().add(tool.createGuard(b, deoptReason, action, leafGraphId));
         }
         ((StructuredGraph) graph()).replaceFixedWithFixed(this, newAnchor);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Fri May 11 16:02:24 2012 +0200
@@ -45,6 +45,11 @@
         return compare;
     }
 
+    public void setCompare(BooleanNode x) {
+        updateUsages(compare, x);
+        compare = x;
+    }
+
     public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double takenProbability) {
         super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {takenProbability, 1 - takenProbability});
         this.compare = condition;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Fri May 11 16:02:24 2012 +0200
@@ -24,10 +24,10 @@
 
 import java.util.*;
 
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.type.*;
 
 /**
  * This class represents a value within the graph, including local variables, phis, and
@@ -41,8 +41,11 @@
      */
     private Stamp stamp;
 
-    @Input private NodeInputList<Node> dependencies;
+    @Input(notDataflow = true) private NodeInputList<Node> dependencies;
 
+    /**
+     * This collection keeps dependencies that should be observed while scheduling (guards, etc.).
+     */
     public NodeInputList<Node> dependencies() {
         return dependencies;
     }
@@ -59,6 +62,12 @@
         assert kind() != null && kind() == kind().stackKind() : kind() + " != " + kind().stackKind();
     }
 
+    public ValueNode(Stamp stamp, List<Node> dependencies) {
+        this.stamp = stamp;
+        this.dependencies = new NodeInputList<>(this, dependencies);
+        assert kind() != null && kind() == kind().stackKind() : kind() + " != " + kind().stackKind();
+    }
+
     public Stamp stamp() {
         return stamp;
     }
@@ -121,7 +130,7 @@
         if (!dependencies.isEmpty()) {
             StringBuilder str = new StringBuilder();
             for (int i = 0; i < dependencies.size(); i++) {
-                str.append(i == 0 ? "" : ", ").append(dependencies.get(i).toString(Verbosity.Id));
+                str.append(i == 0 ? "" : ", ").append(dependencies.get(i) == null ? "null" : dependencies.get(i).toString(Verbosity.Id));
             }
             properties.put("dependencies", str.toString());
         }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Fri May 11 16:02:24 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.calc;
 
+import java.util.*;
+
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
@@ -35,4 +37,8 @@
     public FloatingNode(Stamp stamp, Node... dependencies) {
         super(stamp, dependencies);
     }
+
+    public FloatingNode(Stamp stamp, List<Node> dependencies) {
+        super(stamp, dependencies);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Fri May 11 16:02:24 2012 +0200
@@ -60,6 +60,20 @@
                     return x();
                 }
             }
+            // canonicalize expressions like "(a + 1) + 2"
+            if (x() instanceof IntegerAddNode) {
+                IntegerAddNode other = (IntegerAddNode) x();
+                if (other.y().isConstant()) {
+                    ConstantNode sum;
+                    if (kind() == CiKind.Int) {
+                        sum = ConstantNode.forInt(y().asConstant().asInt() + other.y().asConstant().asInt(), graph());
+                    } else {
+                        assert kind() == CiKind.Long;
+                        sum = ConstantNode.forLong(y().asConstant().asLong() + other.y().asConstant().asLong(), graph());
+                    }
+                    return graph().unique(new IntegerAddNode(kind(), other.x(), sum));
+                }
+            }
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Fri May 11 16:02:24 2012 +0200
@@ -57,6 +57,20 @@
             if (c > 0 && CiUtil.isPowerOf2(c)) {
                 return graph().unique(new LeftShiftNode(kind(), x(), ConstantNode.forInt(CiUtil.log2(c), graph())));
             }
+            // canonicalize expressions like "(a * 1) * 2"
+            if (x() instanceof IntegerMulNode) {
+                IntegerMulNode other = (IntegerMulNode) x();
+                if (other.y().isConstant()) {
+                    ConstantNode sum;
+                    if (kind() == CiKind.Int) {
+                        sum = ConstantNode.forInt(y().asConstant().asInt() * other.y().asConstant().asInt(), graph());
+                    } else {
+                        assert kind() == CiKind.Long;
+                        sum = ConstantNode.forLong(y().asConstant().asLong() * other.y().asConstant().asLong(), graph());
+                    }
+                    return graph().unique(new IntegerMulNode(kind(), other.x(), sum));
+                }
+            }
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Fri May 11 16:02:24 2012 +0200
@@ -28,7 +28,6 @@
 public abstract class AccessNode extends FixedWithNextNode implements Access {
 
     @Input private ValueNode object;
-    @Input private GuardNode guard;
     @Input private LocationNode location;
     private boolean nullCheck;
 
@@ -36,15 +35,6 @@
         return object;
     }
 
-    public GuardNode guard() {
-        return guard;
-    }
-
-    public void setGuard(GuardNode x) {
-        updateUsages(guard, x);
-        guard = x;
-    }
-
     public LocationNode location() {
         return location;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Fri May 11 16:02:24 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.extended;
 
+import java.util.*;
+
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -30,7 +32,6 @@
 public abstract class FloatingAccessNode extends FloatingNode implements Access {
 
     @Input private ValueNode object;
-    @Input private GuardNode guard;
     @Input private LocationNode location;
     private boolean nullCheck;
 
@@ -38,15 +39,6 @@
         return object;
     }
 
-    public GuardNode guard() {
-        return guard;
-    }
-
-    public void setGuard(GuardNode x) {
-        updateUsages(guard, x);
-        guard = x;
-    }
-
     public LocationNode location() {
         return location;
     }
@@ -59,17 +51,21 @@
         this.nullCheck = check;
     }
 
-    public FloatingAccessNode(ValueNode object, GuardNode guard, LocationNode location, Stamp stamp) {
+    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp) {
         super(stamp);
         this.object = object;
-        this.guard = guard;
         this.location = location;
     }
 
-    public FloatingAccessNode(ValueNode object, GuardNode guard, LocationNode location, Stamp stamp, Node... dependencies) {
+    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, Node... dependencies) {
         super(stamp, dependencies);
         this.object = object;
-        this.guard = guard;
+        this.location = location;
+    }
+
+    public FloatingAccessNode(ValueNode object, LocationNode location, Stamp stamp, List<Node> dependencies) {
+        super(stamp, dependencies);
+        this.object = object;
         this.location = location;
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Fri May 11 16:02:24 2012 +0200
@@ -22,18 +22,32 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
+import java.util.*;
+
 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.*;
 
 
 public final class FloatingReadNode extends FloatingAccessNode implements Node.IterableNodeType, LIRLowerable, Canonicalizable {
 
-    public FloatingReadNode(ValueNode object, GuardNode guard, LocationNode location, Stamp stamp, Node... dependencies) {
-        super(object, guard, location, stamp, dependencies);
+    @Input private Node lastLocationAccess;
+
+    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, Node... dependencies) {
+        super(object, location, stamp, dependencies);
+        this.lastLocationAccess = lastLocationAccess;
+    }
+
+    public FloatingReadNode(ValueNode object, LocationNode location, Node lastLocationAccess, Stamp stamp, List<Node> dependencies) {
+        super(object, location, stamp, dependencies);
+        this.lastLocationAccess = lastLocationAccess;
+    }
+
+    public Node lastLocationAccess() {
+        return lastLocationAccess;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java	Fri May 11 16:02:24 2012 +0200
@@ -26,9 +26,11 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.cri.ri.RiType.*;
 
 // TODO (chaeubl) this should be a FloatingNode but Lowering is not possible in that case
-public final class ReadHubNode extends FixedWithNextNode implements Lowerable {
+public final class ReadHubNode extends FixedWithNextNode implements Lowerable, Canonicalizable {
     @Input private ValueNode object;
 
     public ValueNode object() {
@@ -44,4 +46,20 @@
     public void lower(CiLoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        RiResolvedType exactType = object.exactType();
+
+        if (exactType == null && tool.assumptions() != null && object.declaredType() != null) {
+            exactType = object.declaredType().uniqueConcreteSubtype();
+            if (exactType != null) {
+                tool.assumptions().recordConcreteSubtype(object.declaredType(), exactType);
+            }
+        }
+        if (exactType != null) {
+            return ConstantNode.forCiConstant(exactType.getEncoding(Representation.ObjectHub), tool.runtime(), graph());
+        }
+        return this;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Fri May 11 16:02:24 2012 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 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.*;
@@ -40,9 +41,9 @@
     @Override
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId());
+        Node guard = tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId());
         ReadNode read = graph.add(new ReadNode(object(), location(), stamp()));
-        read.setGuard(guard);
+        read.dependencies().add(guard);
 
         graph.replaceFixedWithFixed(this, read);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Fri May 11 16:02:24 2012 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.nodes.extended;
 
 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.*;
@@ -62,9 +63,9 @@
     @Override
     public void lower(CiLoweringTool tool) {
         StructuredGraph graph = (StructuredGraph) graph();
-        GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId());
+        Node guard = tool.createGuard(graph.unique(new NullCheckNode(object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, leafGraphId());
         WriteNode write = graph.add(new WriteNode(object(), value(), location()));
-        write.setGuard(guard);
+        write.dependencies().add(guard);
         graph.replaceFixedWithFixed(this, write);
     }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Fri May 11 16:02:24 2012 +0200
@@ -25,12 +25,12 @@
 import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
 import com.oracle.graal.cri.*;
 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.*;
 
 /**
  * The base class of all instructions that access fields.
@@ -102,6 +102,15 @@
     }
 
     @Override
+    public String toString(Verbosity verbosity) {
+        if (verbosity == Verbosity.Name) {
+            return super.toString(verbosity) + "#" + field.name();
+        } else {
+            return super.toString(verbosity);
+        }
+    }
+
+    @Override
     public boolean verify() {
         assertTrue(object != null, "Access object can not be null");
         return super.verify();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri May 11 14:11:56 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri May 11 16:02:24 2012 +0200
@@ -278,13 +278,7 @@
         } else if (a == null || b == null) {
             return null;
         } else {
-            if (a.isSubtypeOf(b)) {
-                return b;
-            } else if (b.isSubtypeOf(a)) {
-                return a;
-            } else {
-                return null;
-            }
+            return a.leastCommonAncestor(b);
         }
     }
 }