changeset 5392:3f9895797ff4

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 11 May 2012 16:02:24 +0200
parents 5097f21f6c2b (current diff) 8be0c73cf118 (diff)
children 9b44497fef98 afb983c25aa0
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java
diffstat 44 files changed, 448 insertions(+), 248 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri May 11 16:02:24 2012 +0200
@@ -173,9 +173,9 @@
             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);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Fri May 11 16:02:24 2012 +0200
@@ -258,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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Fri May 11 16:02:24 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);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CheckCastEliminationPhase.java	Fri May 11 16:02:24 2012 +0200
@@ -29,13 +29,11 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.PhiNode.*;
 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.ci.*;
 import com.oracle.max.cri.ri.*;
 
 public class CheckCastEliminationPhase extends Phase {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InliningPhase.java	Fri May 11 16:02:24 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;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Fri May 11 16:02:24 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/util/InliningUtil.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Fri May 11 16:02:24 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.graph/src/com/oracle/graal/graph/Graph.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Fri May 11 16:02:24 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/HotSpotDebugConfig.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Fri May 11 16:02:24 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();
                 }
             });
 
@@ -499,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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri May 11 16:02:24 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;
@@ -330,6 +350,7 @@
             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,7 +358,7 @@
                     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 {
@@ -348,7 +369,7 @@
                     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()));
-                    CheckCastNode checkcast = graph.add(new CheckCastNode(arrayElementKlass, null, value));
+                    checkcast = graph.add(new CheckCastNode(arrayElementKlass, null, value));
                     graph.addBeforeFixed(storeIndexed, checkcast);
                     value = checkcast;
                 }
@@ -362,6 +383,9 @@
             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;
@@ -387,6 +411,31 @@
             ReadNode memoryRead = graph.add(new ReadNode(objectClassNode.object(), location, StampFactory.objectNonNull()));
             memoryRead.dependencies().add(tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID));
             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;
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java	Fri May 11 16:00:00 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/cri/CiLoweringTool.java	Fri May 11 16:02:24 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	Fri May 11 16:02:24 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/BeginNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Fri May 11 16:02:24 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/FixedWithNextNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Fri May 11 16:02:24 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/Invoke.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/Invoke.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ScheduledNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Fri May 11 16:02:24 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/ValueProxyNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ValueProxyNode.java	Fri May 11 16:02:24 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/extended/AbstractCallNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java	Fri May 11 16:02:24 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/BoxNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri May 11 16:02:24 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/MembarNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Fri May 11 16:02:24 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/SafeWriteNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Fri May 11 16:02:24 2012 +0200
@@ -27,14 +27,29 @@
 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);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Fri May 11 16:02:24 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/AccessMonitorNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Fri May 11 16:02:24 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/RegisterFinalizerNode.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Fri May 11 16:02:24 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.snippets/src/com/oracle/graal/snippets/Snippets.java	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/FloatingReadTest.java	Fri May 11 16:02:24 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	Fri May 11 16:00:00 2012 +0200
+++ b/mxtool/mx.py	Fri May 11 16:02:24 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