changeset 5408:af76b75d5928

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Mon, 14 May 2012 16:16:22 +0200
parents 9b44497fef98 (diff) 80ae8033fe01 (current diff)
children fc3efebea409
files
diffstat 64 files changed, 1073 insertions(+), 328 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon May 14 16:16:22 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);
             }
@@ -168,10 +173,13 @@
             new GlobalValueNumberingPhase().apply(graph);
         }
 
-        graph.mark();
-        new LoweringPhase(runtime).apply(graph);
-        new CanonicalizerPhase(target, runtime, assumptions, true, null).apply(graph);
+        int mark = graph.getMark();
+        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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon May 14 16:16:22 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;
@@ -256,6 +258,13 @@
     public static int InstanceOfMaxHints = 1;
 
     /**
+     * Use HIR lowering instead of LIR lowering for checkcast instructions.
+     * Only checkcasts in methods in a class whose name contains this option will be HIR lowered.
+     * TDOD (dnsimon) remove once HIR checkcast lowering works reliably
+     */
+    public static String HIRLowerCheckcast;
+
+    /**
      * The profiling info cache directory.
      */
     public static String PICache = null;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Mon May 14 16:16:22 2012 +0200
@@ -836,7 +836,7 @@
             case Virtual:
                 assert callTarget.receiver().kind() == CiKind.Object : callTarget + ": " + callTarget.targetMethod().toString();
                 receiver = toXirArgument(callTarget.receiver());
-                snippet = xir.genInvokeVirtual(site(x.node(), callTarget.receiver()), receiver, targetMethod, x.megamorph());
+                snippet = xir.genInvokeVirtual(site(x.node(), callTarget.receiver()), receiver, targetMethod, x.isMegamorphic());
                 break;
             case Interface:
                 assert callTarget.receiver().kind() == CiKind.Object : callTarget;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Mon May 14 16:16:22 2012 +0200
@@ -37,18 +37,22 @@
     private static final DebugMetric METRIC_CANONICALIZATION_CONSIDERED_NODES = Debug.metric("CanonicalizationConsideredNodes");
     private static final DebugMetric METRIC_SIMPLIFICATION_CONSIDERED_NODES = Debug.metric("SimplificationConsideredNodes");
 
-    private boolean newNodes;
+    private int newNodesMark;
     private final CiTarget target;
     private final CiAssumptions assumptions;
     private final RiRuntime runtime;
     private final IsImmutablePredicate immutabilityPredicate;
 
     public CanonicalizerPhase(CiTarget target, RiRuntime runtime, CiAssumptions assumptions) {
-        this(target, runtime, assumptions, false, null);
+        this(target, runtime, assumptions, -1, null);
     }
 
-    public CanonicalizerPhase(CiTarget target, RiRuntime runtime, CiAssumptions assumptions, boolean newNodes, IsImmutablePredicate immutabilityPredicate) {
-        this.newNodes = newNodes;
+    /**
+     * @param newNodesMark if non-negative, then only the {@linkplain Graph#getNewNodes(int) new nodes} specified by
+     *            this mark are processed otherwise all nodes in the graph are processed
+     */
+    public CanonicalizerPhase(CiTarget target, RiRuntime runtime, CiAssumptions assumptions, int newNodesMark, IsImmutablePredicate immutabilityPredicate) {
+        this.newNodesMark = newNodesMark;
         this.target = target;
         this.assumptions = assumptions;
         this.runtime = runtime;
@@ -57,9 +61,10 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        boolean newNodes = newNodesMark >= 0;
         NodeWorkList nodeWorkList = graph.createNodeWorkList(!newNodes, MAX_ITERATION_PER_NODE);
         if (newNodes) {
-            nodeWorkList.addAll(graph.getNewNodes());
+            nodeWorkList.addAll(graph.getNewNodes(newNodesMark));
         }
 
         canonicalize(graph, nodeWorkList, runtime, target, assumptions, immutabilityPredicate);
@@ -80,7 +85,7 @@
             METRIC_PROCESSED_NODES.increment();
             if (node instanceof Canonicalizable) {
                 METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
-                graph.mark();
+                int mark = graph.getMark();
                 ValueNode canonical = ((Canonicalizable) node).canonical(tool);
 //     cases:                                           original node:
 //                                         |Floating|Fixed-unconnected|Fixed-connected|
@@ -132,7 +137,7 @@
                             }
                         }
                     }
-                    nodeWorkList.addAll(graph.getNewNodes());
+                    nodeWorkList.addAll(graph.getNewNodes(mark));
                 }
             } else if (node instanceof Simplifiable) {
                 Debug.log("Canonicalizer: simplifying %s", node);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java	Mon May 14 16:16:22 2012 +0200
@@ -0,0 +1,320 @@
+/*
+ * 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.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;
+
+    @Override
+    protected void run(StructuredGraph inputGraph) {
+        graph = inputGraph;
+        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	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java	Mon May 14 16:16:22 2012 +0200
@@ -84,10 +84,10 @@
         graph.createNodeMap();
 
         if (hints != null) {
-            scanInvokes((Iterable<? extends Node>) Util.uncheckedCast(this.hints), -1, graph);
+            scanInvokes((Iterable<? extends Node>) Util.uncheckedCast(this.hints), -1);
         } else {
-            scanInvokes(graph.getNodes(InvokeNode.class), 0, graph);
-            scanInvokes(graph.getNodes(InvokeWithExceptionNode.class), 0, graph);
+            scanInvokes(graph.getNodes(InvokeNode.class), 0);
+            scanInvokes(graph.getNodes(InvokeWithExceptionNode.class), 0);
         }
 
         while (!inlineCandidates.isEmpty() && graph.getNodeCount() < GraalOptions.MaximumDesiredSize) {
@@ -101,14 +101,14 @@
             });
 
             if (inline) {
+                int mark = graph.getMark();
                 Iterable<Node> newNodes = null;
                 try {
                     info.inline(graph, runtime, this);
                     Debug.dump(graph, "after %s", info);
-                    // get the new nodes here, the canonicalizer phase will reset the mark
-                    newNodes = graph.getNewNodes();
+                    newNodes = graph.getNewNodes(mark);
                     if (GraalOptions.OptCanonicalizer) {
-                        new CanonicalizerPhase(target, runtime, assumptions, true, null).apply(graph);
+                        new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph);
                     }
 //                    if (GraalOptions.Intrinsify) {
 //                        new IntrinsificationPhase(runtime).apply(graph);
@@ -126,7 +126,7 @@
                 }
 
                 if (newNodes != null && info.level < GraalOptions.MaximumInlineLevel) {
-                    scanInvokes(newNodes, info.level + 1, graph);
+                    scanInvokes(newNodes, info.level + 1);
                 }
             }
         }
@@ -144,11 +144,10 @@
         }
     }
 
-    private void scanInvokes(final Iterable<? extends Node> newNodes, final int level, final StructuredGraph graph) {
+    private void scanInvokes(final Iterable<? extends Node> nodes, final int level) {
         Debug.scope("InliningDecisions", new Runnable() {
             public void run() {
-                graph.mark();
-                for (Node node : newNodes) {
+                for (Node node : nodes) {
                     if (node != null) {
                         if (node instanceof Invoke) {
                             Invoke invoke = (Invoke) node;
@@ -209,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/InsertStateAfterPlaceholderPhase.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Mon May 14 16:16:22 2012 +0200
@@ -29,7 +29,7 @@
 
 public class InsertStateAfterPlaceholderPhase extends Phase {
 
-    private static class PlaceholderNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType, LIRLowerable {
+    private static class PlaceholderNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, LIRLowerable {
         public PlaceholderNode() {
             super(StampFactory.illegal());
         }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Mon May 14 16:16:22 2012 +0200
@@ -27,7 +27,9 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
 /**
@@ -36,9 +38,11 @@
 public class LoweringPhase extends Phase {
 
     private final GraalRuntime runtime;
+    private final CiAssumptions assumptions;
 
-    public LoweringPhase(GraalRuntime runtime) {
+    public LoweringPhase(GraalRuntime runtime, CiAssumptions assumptions) {
         this.runtime = runtime;
+        this.assumptions = assumptions;
     }
 
     @Override
@@ -67,10 +71,19 @@
                 // TODO (thomaswue): Document why this must not be called on floating nodes.
                 throw new UnsupportedOperationException();
             }
+
+            @Override
+            public CiAssumptions assumptions() {
+                return assumptions;
+            }
         };
         for (Node node : processed) {
-            if (node instanceof Lowerable) {
-                assert !(node instanceof FixedNode) || node.predecessor() == null;
+            if (node instanceof CheckCastNode) {
+                // This is a checkcast that was created while lowering some other node (e.g. StoreIndexed).
+                // This checkcast must now be LIR lowered.
+                // TODO (dnsimon) this is temp workaround that will be removed
+            } else if (node instanceof Lowerable) {
+                assert !(node instanceof FixedNode) || node.predecessor() == null : node;
                 ((Lowerable) node).lower(loweringTool);
             }
         }
@@ -135,6 +148,11 @@
                 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/phases/ReadEliminationPhase.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/ReadEliminationPhase.java	Mon May 14 16:16:22 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.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Mon May 14 16:16:22 2012 +0200
@@ -40,6 +40,7 @@
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.max.cri.ci.*;
@@ -287,7 +288,7 @@
             PhiNode exceptionObjectPhi = null;
             if (invoke instanceof InvokeWithExceptionNode) {
                 InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
-                BeginNode exceptionEdge = invokeWithException.exceptionEdge();
+                DispatchBeginNode exceptionEdge = invokeWithException.exceptionEdge();
                 ExceptionObjectNode exceptionObject = (ExceptionObjectNode) exceptionEdge.next();
 
                 exceptionMerge = graph.add(new MergeNode());
@@ -634,7 +635,7 @@
                         return null;
                     }
                 } else {
-                    invoke.setMegamorph(true);
+                    invoke.setMegamorphic(true);
                     if (optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0 || optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
                         // TODO (chaeubl) inlining of multiple methods should work differently
                         // 1. check which methods can be inlined
@@ -785,7 +786,7 @@
         ArrayList<Node> nodes = new ArrayList<>();
         ReturnNode returnNode = null;
         UnwindNode unwindNode = null;
-        BeginNode entryPointNode = inlineGraph.start();
+        StartNode entryPointNode = inlineGraph.start();
         FixedNode firstCFGNode = entryPointNode.next();
         for (Node node : inlineGraph.getNodes()) {
             if (node == entryPointNode || node == entryPointNode.stateAfter()) {
@@ -921,11 +922,12 @@
                     final StructuredGraph snippetGraph,
                     final boolean explodeLoops,
                     final IsImmutablePredicate immutabilityPredicate,
+                    final CiLoweringTool tool,
                     final Object... args) {
         Debug.scope("InliningSnippet", snippetGraph.method(), new Runnable() {
             @Override
             public void run() {
-                inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, args);
+                inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, tool, args);
             }
         });
     }
@@ -935,7 +937,10 @@
                     StructuredGraph snippetGraph,
                     boolean explodeLoops,
                     IsImmutablePredicate immutabilityPredicate,
-                    Object... args) {
+                    CiLoweringTool tool, 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<>();
@@ -957,7 +962,7 @@
         assert localCount == args.length : "snippet argument count mismatch";
         snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements);
         if (!replacements.isEmpty()) {
-            new CanonicalizerPhase(null, runtime, null, false, immutabilityPredicate).apply(snippetCopy);
+            new CanonicalizerPhase(null, runtime, null, -1, immutabilityPredicate).apply(snippetCopy);
         }
 
         // Explode all loops in the snippet if requested
@@ -967,19 +972,23 @@
                 LoopBeginNode loopBegin = loop.loopBegin();
                 SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
                 Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
+                int peel = 0;
                 while (!loopBegin.isDeleted()) {
-                    snippetCopy.mark();
+                    int mark = snippetCopy.getMark();
                     LoopTransformUtil.peel(loop, wholeLoop);
-                    new CanonicalizerPhase(null, runtime, null, true, immutabilityPredicate).apply(snippetCopy);
+                    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 snippets that are to be inlined
+        // Gather the nodes in the snippet that are to be inlined
         ArrayList<Node> nodes = new ArrayList<>();
         ReturnNode returnNode = null;
-        BeginNode entryPointNode = snippetCopy.start();
+        StartNode entryPointNode = snippetCopy.start();
         FixedNode firstCFGNode = entryPointNode.next();
         replacements.clear();
         for (Node node : snippetCopy.getNodes()) {
@@ -1003,21 +1012,39 @@
 
         // 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 : duplicates.values()) {
+        if (tool != null) {
+            boolean innerLowering = false;
+            for (Node node : duplicates.values()) {
+                if (node instanceof Lowerable) {
+                    innerLowering = true;
+                    ((Lowerable) node).lower(tool);
+
+                }
+            }
+            if (innerLowering) {
+                Debug.dump(graph, "After inner lowering");
+            }
+        }
+
+        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;
+                assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + replacee.graph();
                 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);
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValue.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/internal/DebugValue.java	Mon May 14 16:16:22 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.graph/src/com/oracle/graal/graph/Graph.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon May 14 16:16:22 2012 +0200
@@ -45,7 +45,6 @@
     private final ArrayList<Node> nodeCacheFirst;
     private final ArrayList<Node> nodeCacheLast;
     private int deletedNodeCount;
-    private int mark;
     private GraphEventLog eventLog;
 
     ArrayList<Node> usagesDropped = new ArrayList<>();
@@ -221,10 +220,10 @@
     }
 
     /**
-     * @see #getNewNodes()
+     * Gets a mark that can be used with {@link #getNewNodes()}.
      */
-    public void mark() {
-        this.mark = nodeIdCount();
+    public int getMark() {
+        return nodeIdCount();
     }
 
     private class NodeIterator implements Iterator<Node> {
@@ -277,11 +276,10 @@
     }
 
     /**
-     * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#mark() mark}.
-     * @return an {@link Iterable} providing the new nodes
+     * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark() mark}.
      */
-    public NodeIterable<Node> getNewNodes() {
-        final int index = this.mark;
+    public NodeIterable<Node> getNewNodes(int mark) {
+        final int index = mark;
         return new NodeIterable<Node>() {
             @Override
             public Iterator<Node> iterator() {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Mon May 14 16:16:22 2012 +0200
@@ -67,7 +67,7 @@
         return count;
     }
     public boolean isEmpty() {
-        return count() == 0;
+        return !iterator().hasNext();
     }
     public boolean isNotEmpty() {
         return iterator().hasNext();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Mon May 14 16:16:22 2012 +0200
@@ -79,8 +79,6 @@
         cancelled = true;
     }
 
-//    private static PrintStream out = System.out;
-
     public void run() {
         withinEnqueue.set(Boolean.FALSE);
         try {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Mon May 14 16:16:22 2012 +0200
@@ -148,8 +148,7 @@
             return null;
         }
         Debug.setConfig(Debug.fixedConfig(true, true, false, false, dumpHandlers, output));
-        // sync "Exception occured in scope: " with mx/sanitycheck.py::Test.__init__
-        Debug.log(String.format("Exception occured in scope: %s", Debug.currentScope()));
+        Debug.log(String.format("Exception occurred in scope: %s", Debug.currentScope()));
         for (Object o : Debug.context()) {
             Debug.log("Context obj %s", o);
             if (o instanceof Graph) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Mon May 14 16:16:22 2012 +0200
@@ -53,7 +53,6 @@
 
     private final Compiler compiler;
     private IntrinsifyArrayCopyPhase intrinsifyArrayCopy;
-    private LowerCheckCastPhase lowerCheckCastPhase;
 
     public final HotSpotTypePrimitive typeBoolean;
     public final HotSpotTypePrimitive typeChar;
@@ -116,12 +115,8 @@
                 @Override
                 public void run() {
                     VMToCompilerImpl.this.intrinsifyArrayCopy = new IntrinsifyArrayCopyPhase(runtime);
-                    VMToCompilerImpl.this.lowerCheckCastPhase = new LowerCheckCastPhase(runtime);
                     GraalIntrinsics.installIntrinsics(runtime, runtime.getCompiler().getTarget());
-                    Snippets.install(runtime, runtime.getCompiler().getTarget(), new SystemSnippets());
-                    Snippets.install(runtime, runtime.getCompiler().getTarget(), new UnsafeSnippets());
-                    Snippets.install(runtime, runtime.getCompiler().getTarget(), new ArrayCopySnippets());
-                    Snippets.install(runtime, runtime.getCompiler().getTarget(), new CheckCastSnippets());
+                    runtime.installSnippets();
                 }
             });
 
@@ -260,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");
@@ -284,7 +282,7 @@
                         globalMap.group();
                     }
                     globalMap.normalize();
-                    printMap(globalMap, debugValues, 0);
+                    printMap(globalMap, sortedValues, 0);
                 }
             }
         }
@@ -331,6 +329,7 @@
 
         printIndent(level);
         TTY.println("%s", map.getName());
+
         for (DebugValue value : debugValues) {
             long l = map.getCurrentValue(value.getIndex());
             if (l != 0) {
@@ -495,7 +494,6 @@
         if (GraalOptions.Intrinsify) {
             phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy);
         }
-        phasePlan.addPhase(PhasePosition.HIGH_LEVEL, lowerCheckCastPhase);
         return phasePlan;
     }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Mon May 14 16:16:22 2012 +0200
@@ -28,18 +28,24 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 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.*;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.Compiler;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.snippets.*;
 import com.oracle.graal.hotspot.target.amd64.*;
 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.snippets.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ci.CiTargetMethod.Call;
 import com.oracle.max.cri.ci.CiTargetMethod.DataPatch;
@@ -58,6 +64,7 @@
     final HotSpotRegisterConfig regConfig;
     private final HotSpotRegisterConfig globalStubRegConfig;
     private final Compiler compiler;
+    private RiResolvedMethod checkcastSnippet;
 
     public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) {
         this.config = config;
@@ -68,6 +75,19 @@
         System.setProperty(Backend.BACKEND_CLASS_PROPERTY, HotSpotAMD64Backend.class.getName());
     }
 
+    public void installSnippets() {
+        Snippets.install(this, compiler.getTarget(), new SystemSnippets());
+        Snippets.install(this, compiler.getTarget(), new UnsafeSnippets());
+        Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets());
+        Snippets.install(this, compiler.getTarget(), new CheckCastSnippets());
+        try {
+            checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class));
+        } catch (NoSuchMethodException e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+
     @Override
     public int codeOffset() {
         return 0;
@@ -270,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));
@@ -282,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);
 
@@ -316,20 +336,21 @@
             }
         } 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());
             ValueNode value = storeIndexed.value();
+            CheckCastNode checkcast = null;
             ValueNode array = storeIndexed.array();
             if (elementKind == CiKind.Object && !value.isNullConstant()) {
                 // Store check!
@@ -337,24 +358,24 @@
                     RiResolvedType elementType = array.exactType().componentType();
                     if (elementType.superType() != null) {
                         ConstantNode type = ConstantNode.forCiConstant(elementType.getEncoding(Representation.ObjectHub), this, graph);
-                        CheckCastNode checkcast = graph.add(new CheckCastNode(type, elementType, value));
+                        checkcast = graph.add(new CheckCastNode(type, elementType, value));
                         graph.addBeforeFixed(storeIndexed, checkcast);
                         value = checkcast;
                     } else {
                         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()));
-                    CheckCastNode checkcast = graph.add(new CheckCastNode(arrayElementKlass, null, value));
+                    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);
@@ -362,13 +383,16 @@
             if (elementKind == CiKind.Object && !value.isNullConstant()) {
                 graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation)));
             }
+            if (checkcast != null) {
+                checkcast.lower(tool);
+            }
         } else if (n instanceof UnsafeLoadNode) {
             UnsafeLoadNode load = (UnsafeLoadNode) n;
             assert load.kind() != CiKind.Illegal;
             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;
@@ -385,8 +409,33 @@
             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)) {
+                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);
+
+                InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, tool, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
+                new DeadCodeEliminationPhase().apply(graph);
+            }
         } else {
             assert false : "Node implementing Lowerable not handled: " + n;
         }
@@ -396,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
@@ -418,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);
@@ -431,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.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java	Mon May 14 16:16:12 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * 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.hotspot.snippets;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
-import com.oracle.graal.compiler.util.*;
-import com.oracle.graal.cri.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.hotspot.ri.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.criutils.*;
-
-/**
- * Lowers a {@link CheckCastNode} by replacing it with the graph of a {@linkplain CheckCastSnippets checkcast snippet}.
- */
-public class LowerCheckCastPhase extends Phase {
-    private final GraalRuntime runtime;
-    private final RiResolvedMethod checkcast;
-
-    public LowerCheckCastPhase(GraalRuntime runtime) {
-        this.runtime = runtime;
-        try {
-            checkcast = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class));
-        } catch (NoSuchMethodException e) {
-            throw new GraalInternalError(e);
-        }
-    }
-
-    @Override
-    protected void run(StructuredGraph graph) {
-        final Map<CiConstant, CiConstant> hintHubsSet = new IdentityHashMap<>();
-        IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() {
-            public boolean apply(CiConstant constant) {
-                return hintHubsSet.containsKey(constant);
-            }
-        };
-        for (CheckCastNode node : graph.getNodes(CheckCastNode.class)) {
-            ValueNode hub = node.targetClassInstruction();
-            ValueNode object = node.object();
-            CiAssumptions assumptions = null;
-            TypeCheckHints hints = new TypeCheckHints(node.targetClass(), node.profile(), assumptions, GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
-            StructuredGraph snippetGraph = (StructuredGraph) checkcast.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, node, Arrays.toString(hints.types), hints.exact);
-
-            InliningUtil.inlineSnippet(runtime, node, node, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
-        }
-        if (!hintHubsSet.isEmpty()) {
-            Debug.log("Lowered %d checkcasts in %s ", hintHubsSet.size(), graph);
-            new DeadCodeEliminationPhase().apply(graph);
-            new CanonicalizerPhase(null, runtime, null, false, immutabilityPredicate).apply(graph);
-        }
-    }
-}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Mon May 14 16:16:22 2012 +0200
@@ -165,7 +165,7 @@
         frameState.clearNonLiveLocals(blockMap.startBlock.localsLiveIn);
 
         // finish the start block
-        lastInstr.setStateAfter(frameState.create(0));
+        ((StateSplit) lastInstr).setStateAfter(frameState.create(0));
         if (blockMap.startBlock.isLoopHeader) {
             appendGoto(createTarget(blockMap.startBlock, frameState));
         } else {
@@ -241,7 +241,7 @@
         return handler.catchTypeCPI() == 0;
     }
 
-    private BeginNode handleException(ValueNode exceptionObject, int bci) {
+    private DispatchBeginNode handleException(ValueNode exceptionObject, int bci) {
         assert bci == FrameState.BEFORE_BCI || bci == bci() : "invalid bci";
         Debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, profilingInfo.getExceptionSeen(bci));
 
@@ -255,7 +255,7 @@
         FrameStateBuilder dispatchState = frameState.copy();
         dispatchState.clearStack();
 
-        BeginNode dispatchBegin = currentGraph.add(new DispatchBeginNode());
+        DispatchBeginNode dispatchBegin = currentGraph.add(new DispatchBeginNode());
         dispatchBegin.setStateAfter(dispatchState.create(bci));
 
         if (exceptionObject == null) {
@@ -948,7 +948,7 @@
             frameState.pushReturn(resultType, result);
 
         } else {
-            BeginNode exceptionEdge = handleException(null, bci());
+            DispatchBeginNode exceptionEdge = handleException(null, bci());
             InvokeWithExceptionNode invoke = currentGraph.add(new InvokeWithExceptionNode(callTarget, exceptionEdge, bci(), graphId));
             ValueNode result = append(invoke);
             frameState.pushReturn(resultType, result);
@@ -1469,9 +1469,13 @@
                 frameState.clearNonLiveLocals(currentBlock.localsLiveOut);
             }
             if (lastInstr instanceof StateSplit) {
-                StateSplit stateSplit = (StateSplit) lastInstr;
-                if (stateSplit.stateAfter() == null) {
-                    stateSplit.setStateAfter(frameState.create(bci));
+                if (lastInstr.getClass() == BeginNode.class) {
+                    // BeginNodes do not need a frame state
+                } else {
+                    StateSplit stateSplit = (StateSplit) lastInstr;
+                    if (stateSplit.stateAfter() == null) {
+                        stateSplit.setStateAfter(frameState.create(bci));
+                    }
                 }
             }
             if (bci < endBCI) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Mon May 14 16:16:22 2012 +0200
@@ -23,11 +23,13 @@
 package com.oracle.graal.cri;
 
 import com.oracle.graal.graph.*;
+import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
 public interface CiLoweringTool {
     GraalRuntime getRuntime();
     Node getGuardAnchor();
     Node createGuard(Node condition, RiDeoptReason deoptReason, RiDeoptAction action, long leafGraphId);
+    CiAssumptions assumptions();
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Mon May 14 16:16:22 2012 +0200
@@ -0,0 +1,51 @@
+/*
+ * 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;
+
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * Provides an implementation of {@link StateSplit}.
+ */
+public abstract class AbstractStateSplit extends FixedWithNextNode implements StateSplit {
+
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
+
+    public AbstractStateSplit(Stamp stamp) {
+        super(stamp);
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AnchorNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AnchorNode.java	Mon May 14 16:16:22 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/BeginNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Mon May 14 16:16:22 2012 +0200
@@ -31,7 +31,23 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public class BeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Node.IterableNodeType {
+public class BeginNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Simplifiable, Node.IterableNodeType {
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return false;
+    }
+
     public BeginNode() {
         super(StampFactory.illegal());
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Mon May 14 16:16:22 2012 +0200
@@ -24,6 +24,8 @@
 
 /**
  * Base class for {@link BeginNode}s that are associated with a frame state.
+ * TODO (dnsimon) this not needed until {@link BeginNode} no longer implements {@link StateSplit}
+ * which is not possible until loop peeling works without requiring begin nodes to have frames states
  */
 public abstract class BeginStateSplitNode extends BeginNode implements StateSplit {
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Mon May 14 16:16:22 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/FixedWithNextNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Mon May 14 16:16:22 2012 +0200
@@ -22,43 +22,13 @@
  */
 package com.oracle.graal.nodes;
 
-import java.util.*;
-
 import com.oracle.graal.nodes.type.*;
 
 /**
  * Base class of all nodes that are fixed within the control flow graph and have an immediate successor.
- * This class also provides an implementation of {@link StateSplit} without being a {@link StateSplit} itself.
  */
 public abstract class FixedWithNextNode extends FixedNode {
 
-    @Input(notDataflow = true) private FrameState stateAfter;
-
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        assert this instanceof StateSplit : getClass() + " does not implement " + StateSplit.class;
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    // Subclasses that implement StateSplit but do not represent side-effecting instructions must override this.
-    public boolean hasSideEffect() {
-        return true;
-    }
-
-    @Override
-    public Map<Object, Object> getDebugProperties() {
-        Map<Object, Object> debugProperties = super.getDebugProperties();
-        if (stateAfter() != null) {
-            debugProperties.put("stateAfter", stateAfter().toString(Verbosity.Debugger));
-        }
-        return debugProperties;
-    }
-
     public FixedNode next() {
         assert scheduledNext() == null || scheduledNext() instanceof FixedNode : "next() cannot be used while the graph is scheduled";
         return (FixedNode) scheduledNext();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/IfNode.java	Mon May 14 16:16:22 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/Invoke.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Mon May 14 16:16:22 2012 +0200
@@ -55,9 +55,12 @@
 
     void setUseForInlining(boolean value);
 
-    boolean megamorph();
+    /**
+     * True if this invocation is almost certainly megamorphic, false when in doubt.
+     */
+    boolean isMegamorphic();
 
-    void setMegamorph(boolean megamorph);
+    void setMegamorphic(boolean value);
 
     long leafGraphId();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Mon May 14 16:16:22 2012 +0200
@@ -34,12 +34,11 @@
 /**
  * The {@code InvokeNode} represents all kinds of method calls.
  */
-public final class InvokeNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint  {
+public final class InvokeNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint  {
 
     @Input private final MethodCallTargetNode callTarget;
     private final int bci;
-    // megamorph should only be true when the compiler is sure that the call site is megamorph, and false when in doubt
-    private boolean megamorph;
+    private boolean megamorphic;
     private boolean useForInlining;
     private final long leafGraphId;
 
@@ -56,7 +55,7 @@
         this.callTarget = callTarget;
         this.bci = bci;
         this.leafGraphId = leafGraphId;
-        this.megamorph = false;
+        this.megamorphic = false;
         this.useForInlining = true;
     }
 
@@ -65,13 +64,13 @@
     }
 
     @Override
-    public boolean megamorph() {
-        return megamorph;
+    public boolean isMegamorphic() {
+        return megamorphic;
     }
 
     @Override
-    public void setMegamorph(boolean megamorph) {
-        this.megamorph = megamorph;
+    public void setMegamorphic(boolean value) {
+        this.megamorphic = value;
     }
 
     public boolean useForInlining() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Mon May 14 16:16:22 2012 +0200
@@ -39,7 +39,7 @@
     @Input private FrameState stateAfter;
     private final int bci;
     // megamorph should only be true when the compiler is sure that the call site is megamorph, and false when in doubt
-    private boolean megamorph;
+    private boolean megamorphic;
     private boolean useForInlining;
     private final long leafGraphId;
 
@@ -48,17 +48,17 @@
      * @param blockSuccessors
      * @param branchProbability
      */
-    public InvokeWithExceptionNode(MethodCallTargetNode callTarget, BeginNode exceptionEdge, int bci, long leafGraphId) {
+    public InvokeWithExceptionNode(MethodCallTargetNode callTarget, DispatchBeginNode exceptionEdge, int bci, long leafGraphId) {
         super(callTarget.returnStamp(), new BeginNode[]{null, exceptionEdge}, new double[]{1.0, 0.0});
         this.bci = bci;
         this.callTarget = callTarget;
         this.leafGraphId = leafGraphId;
-        this.megamorph = true;
+        this.megamorphic = true;
         this.useForInlining = true;
     }
 
-    public BeginNode exceptionEdge() {
-        return blockSuccessor(EXCEPTION_EDGE);
+    public DispatchBeginNode exceptionEdge() {
+        return (DispatchBeginNode) blockSuccessor(EXCEPTION_EDGE);
     }
 
     public void setExceptionEdge(BeginNode x) {
@@ -78,13 +78,13 @@
     }
 
     @Override
-    public boolean megamorph() {
-        return megamorph;
+    public boolean isMegamorphic() {
+        return megamorphic;
     }
 
     @Override
-    public void setMegamorph(boolean megamorph) {
-        this.megamorph = megamorph;
+    public void setMegamorphic(boolean value) {
+        this.megamorphic = value;
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Mon May 14 16:16:22 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes;
 
+import java.util.*;
+
 import com.oracle.graal.graph.*;
 
 public class ScheduledNode extends Node {
@@ -36,4 +38,17 @@
         updatePredecessors(scheduledNext, x);
         scheduledNext = x;
     }
+
+    @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> debugProperties = super.getDebugProperties();
+        if (this instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) this;
+            if (stateSplit.stateAfter() != null) {
+                debugProperties.put("stateAfter", stateSplit.stateAfter().toString(Verbosity.Debugger));
+            }
+        }
+        return debugProperties;
+    }
+
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Mon May 14 16:16:22 2012 +0200
@@ -40,7 +40,7 @@
 
     public static final long INVALID_GRAPH_ID = -1;
     private static final AtomicLong uniqueGraphIds = new AtomicLong();
-    private final BeginNode start;
+    private final StartNode start;
     private final RiResolvedMethod method;
     private final long graphId;
 
@@ -94,7 +94,7 @@
         return buf.toString();
     }
 
-    public BeginNode start() {
+    public StartNode start() {
         return start;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueNode.java	Mon May 14 16:16:22 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/ValueProxyNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Mon May 14 16:16:22 2012 +0200
@@ -27,8 +27,11 @@
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
 
-
-
+/**
+ * A value proxy that is inserted in the frame state of a loop exit for any value that is
+ * created inside the loop (i.e. was not live on entry to the loop) and is (potentially)
+ * used after the loop.
+ */
 public class ValueProxyNode extends FloatingNode implements Node.IterableNodeType, ValueNumberable {
     @Input(notDataflow = true) private BeginNode proxyPoint;
     @Input private ValueNode value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/FloatingNode.java	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerAddNode.java	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/IntegerMulNode.java	Mon May 14 16:16:22 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/AbstractCallNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java	Mon May 14 16:16:22 2012 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class AbstractCallNode extends FixedWithNextNode implements StateSplit, MemoryCheckpoint {
+public abstract class AbstractCallNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint {
 
     @Input
     protected final NodeInputList<ValueNode> arguments;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Mon May 14 16:16:22 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/BoxNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Mon May 14 16:16:22 2012 +0200
@@ -22,16 +22,16 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
 
 
-public final class BoxNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType {
+public final class BoxNode extends AbstractStateSplit implements StateSplit, Node.IterableNodeType {
 
     @Input private ValueNode source;
     private int bci;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingAccessNode.java	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/FloatingReadNode.java	Mon May 14 16:16:22 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/MembarNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Mon May 14 16:16:22 2012 +0200
@@ -30,7 +30,7 @@
 /**
  * Creates a memory barrier.
  */
-public class MembarNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
+public class MembarNode extends AbstractStateSplit implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     private final int barriers;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ReadHubNode.java	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeReadNode.java	Mon May 14 16:16:22 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	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Mon May 14 16:16:22 2012 +0200
@@ -23,17 +23,33 @@
 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.*;
+import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ci.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ri.*;
 
 
 public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable{
 
     @Input private ValueNode value;
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
 
     public SafeWriteNode(ValueNode object, ValueNode value, LocationNode location, long leafGraphId) {
         super(object, location, StampFactory.forKind(CiKind.Void), leafGraphId);
@@ -47,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/extended/UnsafeStoreNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Mon May 14 16:16:22 2012 +0200
@@ -38,6 +38,21 @@
     @Input private ValueNode value;
     private final int displacement;
     private final CiKind storeKind;
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
 
     public UnsafeStoreNode(ValueNode object, int displacement, ValueNode offset, ValueNode value, CiKind kind) {
         super(StampFactory.illegal());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Mon May 14 16:16:22 2012 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.type.*;
 
 
-public final class WriteMemoryCheckpointNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
+public final class WriteMemoryCheckpointNode extends AbstractStateSplit implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     public WriteMemoryCheckpointNode() {
         this(StampFactory.illegal());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Mon May 14 16:16:22 2012 +0200
@@ -22,14 +22,29 @@
  */
 package com.oracle.graal.nodes.extended;
 
-import com.oracle.max.cri.ci.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
 
 
 public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable {
     @Input private ValueNode value;
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
 
     public ValueNode value() {
         return value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Mon May 14 16:16:22 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/java/AccessMonitorNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Mon May 14 16:16:22 2012 +0200
@@ -43,7 +43,7 @@
  * {@link MonitorEnterNode}. Optimization phases are free to throw {@link CiBailout} if they detect such cases.
  * Otherwise, they are detected during LIR construction.
  */
-public abstract class AccessMonitorNode extends FixedWithNextNode implements StateSplit, MemoryCheckpoint {
+public abstract class AccessMonitorNode extends AbstractStateSplit implements StateSplit, MemoryCheckpoint {
 
     @Input private ValueNode object;
     private boolean eliminated;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Mon May 14 16:16:22 2012 +0200
@@ -22,6 +22,7 @@
  */
 package com.oracle.graal.nodes.java;
 
+import com.oracle.graal.cri.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
@@ -34,7 +35,7 @@
 /**
  * Implements a type check that results in a {@link ClassCastException} if it fails.
  */
-public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable {
+public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Lowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable {
 
     @Input private ValueNode object;
     @Input private ValueNode targetClassInstruction;
@@ -60,6 +61,11 @@
     }
 
     @Override
+    public void lower(CiLoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+
+    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitCheckCast(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Mon May 14 16:16:22 2012 +0200
@@ -33,7 +33,7 @@
  * Represents an atomic compare-and-swap operation
  * The result is a boolean that contains whether the value matched the expected value.
  */
-public class CompareAndSwapNode extends FixedWithNextNode implements StateSplit, LIRLowerable, Lowerable, MemoryCheckpoint {
+public class CompareAndSwapNode extends AbstractStateSplit implements StateSplit, LIRLowerable, Lowerable, MemoryCheckpoint {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Mon May 14 16:16:22 2012 +0200
@@ -31,7 +31,7 @@
 /**
  * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler.
  */
-public class ExceptionObjectNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
+public class ExceptionObjectNode extends AbstractStateSplit implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     /**
      * Constructs a new ExceptionObject instruction.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/IsTypeNode.java	Mon May 14 16:16:22 2012 +0200
@@ -28,6 +28,7 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
+import com.oracle.max.cri.ri.RiType.Representation;
 
 public final class IsTypeNode extends BooleanNode implements Canonicalizable, LIRLowerable {
 
@@ -62,6 +63,13 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
+        if (objectClass().isConstant()) {
+            CiConstant constant = objectClass().asConstant();
+            CiConstant typeHub = type.getEncoding(Representation.ObjectHub);
+            assert constant.kind == typeHub.kind;
+            return ConstantNode.forBoolean(constant.equivalent(typeHub), graph());
+        }
+        // TODO(ls) since a ReadHubNode with an exactType should canonicalize itself to a constant this should actually never happen, maybe turn into an assertion?
         RiResolvedType exactType = objectClass() instanceof ReadHubNode ? ((ReadHubNode) objectClass()).object().exactType() : null;
         if (exactType != null) {
             return ConstantNode.forBoolean(exactType == type(), graph());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Mon May 14 16:16:22 2012 +0200
@@ -31,7 +31,7 @@
 /**
  * This node is used to perform the finalizer registration at the end of the java.lang.Object constructor.
  */
-public final class RegisterFinalizerNode extends FixedWithNextNode implements StateSplit, Canonicalizable, LIRLowerable {
+public final class RegisterFinalizerNode extends AbstractStateSplit implements StateSplit, Canonicalizable, LIRLowerable {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Mon May 14 16:16:22 2012 +0200
@@ -32,6 +32,21 @@
 public final class StoreFieldNode extends AccessFieldNode implements StateSplit {
 
     @Input private ValueNode value;
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
 
     public ValueNode value() {
         return value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Mon May 14 16:16:22 2012 +0200
@@ -22,11 +22,11 @@
  */
 package com.oracle.graal.nodes.java;
 
-import com.oracle.max.cri.ci.*;
 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.*;
 
 /**
  * The {@code StoreIndexedNode} represents a write to an array element.
@@ -34,6 +34,21 @@
 public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable {
 
     @Input private ValueNode value;
+    @Input(notDataflow = true) private FrameState stateAfter;
+
+    public FrameState stateAfter() {
+        return stateAfter;
+    }
+
+    public void setStateAfter(FrameState x) {
+        assert x == null || x.isAlive() : "frame state must be in a graph";
+        updateUsages(stateAfter, x);
+        stateAfter = x;
+    }
+
+    public boolean hasSideEffect() {
+        return true;
+    }
 
     public ValueNode value() {
         return value;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Mon May 14 16:16:22 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);
         }
     }
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Mon May 14 16:16:22 2012 +0200
@@ -108,7 +108,7 @@
                     MethodCallTargetNode callTarget = invoke.callTarget();
                     RiResolvedMethod targetMethod = callTarget.targetMethod();
                     RiResolvedType holder = targetMethod.holder();
-                    if (holder.isSubtypeOf(runtime.getType(SnippetsInterface.class))) {
+                    if (enclosedInSnippetsClass(holder)) {
                         StructuredGraph targetGraph = (StructuredGraph) targetMethod.compilerStorage().get(Graph.class);
                         if (targetGraph == null) {
                             targetGraph = buildSnippetGraph(targetMethod, runtime, target, pool);
@@ -140,6 +140,17 @@
 
                 return graph;
             }
+
+            private boolean enclosedInSnippetsClass(RiResolvedType holder) {
+                Class enclosingClass = holder.toJava();
+                while (enclosingClass != null) {
+                    if (SnippetsInterface.class.isAssignableFrom(enclosingClass)) {
+                        return true;
+                    }
+                    enclosingClass = enclosingClass.getEnclosingClass();
+                }
+                return false;
+            }
         });
 
     }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/FloatingReadTest.java	Mon May 14 16:16:12 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/FloatingReadTest.java	Mon May 14 16:16:22 2012 +0200
@@ -52,7 +52,7 @@
 
     private void test(String snippet) {
         StructuredGraph graph = parse(snippet);
-        new LoweringPhase(runtime()).apply(graph);
+        new LoweringPhase(runtime(), null).apply(graph);
         new FloatingReadPhase().apply(graph);
 
         ReturnNode returnNode = null;
--- a/mxtool/mx.py	Mon May 14 16:16:12 2012 +0200
+++ b/mxtool/mx.py	Mon May 14 16:16:22 2012 +0200
@@ -1685,6 +1685,9 @@
     if suite is None:
         suite = _mainSuite
 
+    def println(out, obj):
+        out.write(str(obj) + '\n')
+
     updated = False
     for p in projects():
         if p.native:
@@ -1898,60 +1901,94 @@
     parser.add_argument('--projects', action='store', help='comma separated projects to process (omit to process all projects)')
     parser.add_argument('--argfile', action='store', help='name of file containing extra javadoc options')
     parser.add_argument('-m', '--memory', action='store', help='-Xmx value to pass to underlying JVM')
-    
+    parser.add_argument('--wiki', action='store_true', help='generate Confluence Wiki format for package-info.java files')
+    parser.add_argument('--packages', action='store', help='comma separated packages to process (omit to process all packages)')
+
     args = parser.parse_args(args)
-    
+
     # build list of projects to be processed
     candidates = sorted_deps()
     if args.projects is not None:
         candidates = [project(name) for name in args.projects.split(',')]
-        
+
+    # optionally restrict packages within a project (most useful for wiki)
+    packages = []
+    if args.packages is not None:
+        packages = [name for name in args.packages.split(',')]
+
+    # the WikiDoclet cannot see the -classpath argument passed to javadoc so we pass the
+    # full list of projects as an explicit argument, thereby enabling it to map classes
+    # to projects, which is needed to generate Wiki links to the source code.
+    # There is no virtue in running the doclet on dependent projects as there are
+    # no generated links between Wiki pages
+    docletArgs = []
+    if args.wiki:
+        docDir = 'wikidoc'
+        toolsDir = project('com.oracle.max.tools').output_dir()
+        baseDir = project('com.oracle.max.base').output_dir()
+        dp = os.pathsep.join([toolsDir, baseDir])
+        project_list = ','.join(p.name for p in sorted_deps())
+        docletArgs = ['-docletpath', dp, '-doclet', 'com.oracle.max.tools.javadoc.wiki.WikiDoclet', '-projects', project_list]
+    else:
+        docDir = 'javadoc'
+
+    def check_package_list(p):
+        if args.wiki:
+            return True
+        else:
+            return not exists(join(p.dir, docDir, 'package-list'))
+
     def assess_candidate(p, projects):
         if p in projects:
             return False
-        if args.force or args.unified or not exists(join(p.dir, 'javadoc', 'package-list')):
+        if args.force or args.unified or check_package_list(p):
             projects.append(p)
             return True
         return False
-        
+
     projects = []
     for p in candidates:
         if not p.native:
-            deps = p.all_deps([], includeLibs=False, includeSelf=False)
-            for d in deps:
-                assess_candidate(d, projects)
+            if not args.wiki:
+                deps = p.all_deps([], includeLibs=False, includeSelf=False)
+                for d in deps:
+                    assess_candidate(d, projects)
             if not assess_candidate(p, projects):
                 log('[package-list file exists - skipping {0}]'.format(p.name))
 
-    
+
     def find_packages(sourceDirs, pkgs=set()):
         for sourceDir in sourceDirs:
             for root, _, files in os.walk(sourceDir):
                 if len([name for name in files if name.endswith('.java')]) != 0:
-                    pkgs.add(root[len(sourceDir) + 1:].replace('/','.'))
+                    pkg = root[len(sourceDir) + 1:].replace('/','.')
+                    if (len(packages) == 0) | (pkg in packages):
+                        pkgs.add(pkg)
         return pkgs
 
     extraArgs = []
     if args.argfile is not None:
         extraArgs += ['@' + args.argfile]
+    memory = '2g'
     if args.memory is not None:
-        extraArgs.append('-J-Xmx' + args.memory)
+        memory = args.memory
+    memory = '-J-Xmx' + memory
 
     if not args.unified:
         for p in projects:
             pkgs = find_packages(p.source_dirs(), set())
             deps = p.all_deps([], includeLibs=False, includeSelf=False)
-            links = ['-link', 'http://docs.oracle.com/javase/6/docs/api/']
-            out = join(p.dir, 'javadoc')
+            links = ['-link', 'http://docs.oracle.com/javase/' + str(p.javaCompliance.value) + '/docs/api/']
+            out = join(p.dir, docDir)
             for d in deps:
-                depOut = join(d.dir, 'javadoc')
+                depOut = join(d.dir, docDir)
                 links.append('-link')
                 links.append(os.path.relpath(depOut, out))
             cp = classpath(p.name, includeSelf=True)
             sp = os.pathsep.join(p.source_dirs())
-            log('Generating javadoc for {0} in {1}'.format(p.name, out))
-            run([java().javadoc, '-J-Xmx2g', '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + links + extraArgs + list(pkgs))
-            log('Generated javadoc for {0} in {1}'.format(p.name, out))
+            log('Generating {2} for {0} in {1}'.format(p.name, out, docDir))
+            run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs))
+            log('Generated {2} for {0} in {1}'.format(p.name, out, docDir))
     else:
         pkgs = set()
         sp = []
@@ -1960,14 +1997,14 @@
             find_packages(p.source_dirs(), pkgs)
             sp += p.source_dirs()
             names.append(p.name)
-            
-        links = ['-link', 'http://docs.oracle.com/javase/6/docs/api/']
-        out = join(_mainSuite.dir, 'javadoc')
+
+        links = ['-link', 'http://docs.oracle.com/javase/' + str(_java.javaCompliance.value) + '/docs/api/']
+        out = join(_mainSuite.dir, docDir)
         cp = classpath()
         sp = os.pathsep.join(sp)
-        log('Generating javadoc for {0} in {1}'.format(', '.join(names), out))
-        run([java().javadoc, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + links + extraArgs + list(pkgs))
-        log('Generated javadoc for {0} in {1}'.format(', '.join(names), out))
+        log('Generating {2} for {0} in {1}'.format(', '.join(names), out, docDir))
+        run([java().javadoc, memory, '-classpath', cp, '-quiet', '-d', out, '-sourcepath', sp] + docletArgs + links + extraArgs + list(pkgs))
+        log('Generated {2} for {0} in {1}'.format(', '.join(names), out, docDir))
 
 def javap(args):
     """launch javap with a -classpath option denoting all available classes