changeset 5444:0368c19fc175

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 25 May 2012 11:44:44 +0200
parents 141817e206d4 (current diff) ecba62805b64 (diff)
children 56f4afcf71f7
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java
diffstat 26 files changed, 947 insertions(+), 426 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingReadPhase.java	Fri May 25 11:44:44 2012 +0200
@@ -157,7 +157,7 @@
                 if (anchor == null) {
                     anchor = graph.add(new ValueAnchorNode());
                 }
-                anchor.addAnchoredValue(guard);
+                anchor.addAnchoredNode(guard);
             }
             if (anchor != null) {
                 graph.addAfterFixed(readNode, anchor);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/LoweringPhase.java	Fri May 25 11:44:44 2012 +0200
@@ -29,7 +29,6 @@
 import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
@@ -111,27 +110,6 @@
         }
     }
 
-    protected void run0(final StructuredGraph graph) {
-        ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, true);
-
-        NodeBitMap processed = graph.createNodeBitMap();
-        NodeBitMap activeGuards = graph.createNodeBitMap();
-        processBlock(cfg.getStartBlock(), activeGuards, processed, null);
-
-        processed.negate();
-        final CiLoweringTool loweringTool = new LoweringToolBase();
-        for (Node node : processed) {
-            if (node instanceof CheckCastNode) {
-                // This is a checkcast that was created while lowering some other node (e.g. StoreIndexed).
-                // 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);
-            }
-        }
-    }
-
     private void processBlock(Block block, NodeBitMap activeGuards, NodeBitMap processed, FixedNode parentAnchor) {
 
         FixedNode anchor = parentAnchor;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Fri May 25 11:44:44 2012 +0200
@@ -27,14 +27,10 @@
 import java.util.concurrent.*;
 
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.loop.*;
 import com.oracle.graal.compiler.phases.*;
-import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Node.Verbosity;
-import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.extended.*;
@@ -906,160 +902,6 @@
         }
     }
 
-    /**
-     * Performs replacement of a node with a snippet graph.
-     * @param replacee the node that will be replaced
-     * @param anchor the control flow replacee
-     * @param snippetGraph the graph that the replacee will be replaced with
-     * @param explodeLoops specifies if all the loops in the snippet graph are counted loops that must be completely unrolled
-     * @param args
-     */
-    public static void inlineSnippet(final RiRuntime runtime,
-                    final Node replacee,
-                    final FixedWithNextNode anchor,
-                    final StructuredGraph snippetGraph,
-                    final boolean explodeLoops,
-                    final IsImmutablePredicate immutabilityPredicate,
-                    final Object... args) {
-        Debug.scope("InliningSnippet", snippetGraph.method(), new Runnable() {
-            @Override
-            public void run() {
-                inlineSnippet0(runtime, replacee, anchor, snippetGraph, explodeLoops, immutabilityPredicate, args);
-            }
-        });
-    }
-    private static void inlineSnippet0(RiRuntime runtime,
-                    Node replacee,
-                    FixedWithNextNode anchor,
-                    StructuredGraph snippetGraph,
-                    boolean explodeLoops,
-                    IsImmutablePredicate immutabilityPredicate,
-                    Object... args) {
-
-        Debug.dump(replacee.graph(), "Before lowering %s", replacee);
-
-        // Copy snippet graph, replacing parameters with given args in the process
-        StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
-        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
-        replacements.put(snippetGraph.start(), snippetCopy.start());
-        int localCount = 0;
-        for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) {
-            int index = local.index();
-            if (args[index] instanceof CiConstant) {
-                CiConstant arg = (CiConstant) args[index];
-                assert arg.kind.stackKind() == local.kind() : arg.kind + " != " + local.kind();
-                ConstantNode argNode = ConstantNode.forCiConstant(arg, runtime, snippetCopy);
-                replacements.put(local, argNode);
-                args[index] = null;
-            } else {
-                assert args[index] instanceof ValueNode;
-            }
-            localCount++;
-        }
-        assert localCount == args.length : "snippet argument count mismatch";
-        snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements);
-        if (!replacements.isEmpty()) {
-            new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy);
-        }
-
-        // Explode all loops in the snippet if requested
-        if (explodeLoops && snippetCopy.hasLoops()) {
-            ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false);
-            for (Loop loop : cfg.getLoops()) {
-                LoopBeginNode loopBegin = loop.loopBegin();
-                SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
-                Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
-                int peel = 0;
-                while (!loopBegin.isDeleted()) {
-                    int mark = snippetCopy.getMark();
-                    LoopTransformUtil.peel(loop, wholeLoop);
-                    Debug.dump(snippetCopy, "After peel %d", peel);
-                    new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy);
-                    peel++;
-                }
-                Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
-            }
-            new DeadCodeEliminationPhase().apply(snippetCopy);
-        }
-
-        // Gather the nodes in the snippet that are to be inlined
-        ArrayList<Node> nodes = new ArrayList<>();
-        ReturnNode returnNode = null;
-        StartNode entryPointNode = snippetCopy.start();
-        FixedNode firstCFGNode = entryPointNode.next();
-        replacements.clear();
-        for (Node node : snippetCopy.getNodes()) {
-            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
-                // Do nothing.
-            } else if (node instanceof LocalNode) {
-                LocalNode local = (LocalNode) node;
-                int index = local.index();
-                assert args[index] instanceof ValueNode;
-                ValueNode arg = (ValueNode) args[index];
-                assert arg.kind() == local.kind();
-                replacements.put(node, arg);
-                args[index] = null;
-            } else {
-                nodes.add(node);
-                if (node instanceof ReturnNode) {
-                    returnNode = (ReturnNode) node;
-                }
-            }
-        }
-
-        // Inline the gathered snippet nodes
-        StructuredGraph graph = (StructuredGraph) replacee.graph();
-        int mark = graph.getMark();
-        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
-        Debug.dump(graph, "After inlining snippet %s", snippetCopy.method());
-
-        // Remove all frame states from the inlined snippet graph. Snippets must be atomic (i.e. free
-        // of side-effects that prevent deoptimizing to a point before the snippet).
-        for (Node node : graph.getNewNodes(mark)) {
-            if (node instanceof StateSplit) {
-                StateSplit stateSplit = (StateSplit) node;
-                FrameState frameState = stateSplit.stateAfter();
-                assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + frameState.toString(Verbosity.Debugger);
-                if (frameState != null) {
-                    stateSplit.setStateAfter(null);
-                }
-            }
-        }
-
-        Debug.dump(graph, "After removing frame states");
-
-        // Rewire the control flow graph around the replacee
-        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
-        anchor.replaceAtPredecessors(firstCFGNodeDuplicate);
-        FixedNode next = anchor.next();
-        anchor.setNext(null);
-
-        // Replace all usages of the replacee with the value returned by the snippet
-        Node returnValue = null;
-        if (returnNode != null) {
-            if (returnNode.result() instanceof LocalNode) {
-                returnValue = replacements.get(returnNode.result());
-            } else {
-                returnValue = duplicates.get(returnNode.result());
-            }
-            assert returnValue != null || replacee.usages().isEmpty();
-            replacee.replaceAtUsages(returnValue);
-
-            Node returnDuplicate = duplicates.get(returnNode);
-            returnDuplicate.clearInputs();
-            returnDuplicate.replaceAndDelete(next);
-        }
-
-        // Remove the replacee from its graph
-        replacee.clearInputs();
-        replacee.replaceAtUsages(null);
-        if (replacee instanceof FixedNode) {
-            GraphUtil.killCFG((FixedNode) replacee);
-        } else {
-            replacee.safeDelete();
-        }
-    }
-
     public static void receiverNullCheck(Invoke invoke) {
         MethodCallTargetNode callTarget = invoke.callTarget();
         StructuredGraph graph = (StructuredGraph) invoke.graph();
--- a/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugDumpScope.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.debug/src/com/oracle/graal/debug/DebugDumpScope.java	Fri May 25 11:44:44 2012 +0200
@@ -22,16 +22,24 @@
  */
 package com.oracle.graal.debug;
 
-public final class DebugDumpScope {
+public class DebugDumpScope {
+
+    public final String name;
 
-    private final String name;
+    /**
+     * Specifies if this scope decorates an inner scope.
+     * A hierarchical or tree representation of nested scopes may choose to represent
+     * a decorator scope at the same level as the scope it decorates.
+     */
+    public final boolean decorator;
 
     public DebugDumpScope(String name) {
-        this.name = name;
+        this(name, false);
     }
 
-    public String getName() {
-        return name;
+    public DebugDumpScope(String name, boolean decorator) {
+        this.name = name;
+        this.decorator = decorator;
     }
 
     @Override
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Fri May 25 11:44:44 2012 +0200
@@ -509,7 +509,11 @@
      * @param replacements the replacement map (can be null if no replacement is to be performed)
      * @return a map which associates the original nodes from {@code nodes} to their duplicates
      */
+    @SuppressWarnings("all")
     public Map<Node, Node> addDuplicates(Iterable<Node> newNodes, Map<Node, Node> replacements) {
+        if (replacements == null) {
+            replacements = Collections.emptyMap();
+        }
         return NodeClass.addGraphDuplicate(this, newNodes, replacements);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/DistinctPredicatedProxyNodeIterator.java	Fri May 25 11:44:44 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.graph.iterators;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+
+
+public class DistinctPredicatedProxyNodeIterator<T extends Node> extends PredicatedProxyNodeIterator<T> {
+    private NodeBitMap visited;
+
+    public DistinctPredicatedProxyNodeIterator(NodePredicate until, Iterator<T> iterator, NodePredicate predicate) {
+        super(until, iterator, predicate);
+    }
+
+    @Override
+    protected void forward() {
+        if (current == null) {
+            super.forward();
+            while (!accept(current)) {
+                current = null;
+                super.forward();
+            }
+        }
+    }
+
+    private boolean accept(T n) {
+        if (n == null) {
+            return true;
+        }
+        if (visited == null) {
+            visited = n.graph().createNodeBitMap(true);
+        }
+        boolean accept = !visited.isMarked(n);
+        visited.mark(n);
+        return accept;
+    }
+}
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/FilteredNodeIterable.java	Fri May 25 11:44:44 2012 +0200
@@ -30,6 +30,7 @@
     private final NodeIterable<T> nodeIterable;
     private NodePredicate predicate = NodePredicates.alwaysTrue();
     private NodePredicate until = NodePredicates.isNull();
+    private boolean distinct;
     public FilteredNodeIterable(NodeIterable<T> nodeIterable) {
         this.nodeIterable = nodeIterable;
     }
@@ -52,9 +53,23 @@
         return this;
     }
     @Override
+    public FilteredNodeIterable<T> nonNull() {
+        this.predicate = this.predicate.or(NodePredicates.isNotNull());
+        return this;
+    }
+    @Override
+    public FilteredNodeIterable<T> distinct() {
+        distinct = true;
+        return this;
+    }
+    @Override
     public Iterator<T> iterator() {
         final Iterator<T> iterator = nodeIterable.iterator();
-        return new PredicatedProxyNodeIterator<>(until, iterator, predicate);
+        if (distinct) {
+            return new DistinctPredicatedProxyNodeIterator<>(until, iterator, predicate);
+        } else {
+            return new PredicatedProxyNodeIterator<>(until, iterator, predicate);
+        }
     }
 
     @SuppressWarnings("unchecked")
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Fri May 25 11:44:44 2012 +0200
@@ -46,6 +46,9 @@
     public FilteredNodeIterable<T> nonNull() {
         return new FilteredNodeIterable<>(this).and(NodePredicates.isNotNull());
     }
+    public FilteredNodeIterable<T> distinct() {
+        return new FilteredNodeIterable<>(this).distinct();
+    }
     public List<T> snapshot() {
         ArrayList<T> list = new ArrayList<>();
         for (T n : this) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/PredicatedProxyNodeIterator.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/PredicatedProxyNodeIterator.java	Fri May 25 11:44:44 2012 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -26,7 +26,7 @@
 
 import com.oracle.graal.graph.*;
 
-public final class PredicatedProxyNodeIterator<T extends Node> extends NodeIterator<T> {
+public class PredicatedProxyNodeIterator<T extends Node> extends NodeIterator<T> {
     private final Iterator<T> iterator;
     private final NodePredicate predicate;
     private final NodePredicate until;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Fri May 25 11:44:44 2012 +0200
@@ -111,7 +111,7 @@
             CiTargetMethod result = null;
             TTY.Filter filter = new TTY.Filter(GraalOptions.PrintFilter, method);
             try {
-                result = Debug.scope("Compiling", new Callable<CiTargetMethod>() {
+                result = Debug.scope("Compiling", new DebugDumpScope(String.valueOf(id), true), new Callable<CiTargetMethod>() {
 
                     @Override
                     public CiTargetMethod call() throws Exception {
@@ -148,7 +148,7 @@
     }
 
     private void installMethod(final CiTargetMethod tm) {
-        Debug.scope("CodeInstall", new Object[] {compiler.getCompiler(), method}, new Runnable() {
+        Debug.scope("CodeInstall", new Object[] {new DebugDumpScope(String.valueOf(id), true), compiler.getCompiler(), method}, new Runnable() {
             @Override
             public void run() {
                 final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java	Fri May 25 11:44:44 2012 +0200
@@ -40,7 +40,7 @@
      */
     public final Class javaMirror;
 
-    HotSpotKlassOop(Compiler compiler, Class javaMirror) {
+    public HotSpotKlassOop(Compiler compiler, Class javaMirror) {
         super(compiler);
         this.javaMirror = javaMirror;
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Fri May 25 11:44:44 2012 +0200
@@ -28,10 +28,8 @@
 import java.util.*;
 
 import com.oracle.graal.compiler.*;
-import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.target.*;
-import com.oracle.graal.compiler.util.*;
 import com.oracle.graal.cri.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
@@ -65,7 +63,7 @@
     final HotSpotRegisterConfig regConfig;
     private final HotSpotRegisterConfig globalStubRegConfig;
     private final Compiler compiler;
-    private RiResolvedMethod checkcastSnippet;
+    private CheckCastSnippets.Templates checkcasts;
 
     public HotSpotRuntime(HotSpotVMConfig config, Compiler compiler) {
         this.config = config;
@@ -81,15 +79,7 @@
         Snippets.install(this, compiler.getTarget(), new UnsafeSnippets());
         Snippets.install(this, compiler.getTarget(), new ArrayCopySnippets());
         Snippets.install(this, compiler.getTarget(), new CheckCastSnippets());
-        try {
-            if (GraalOptions.CheckcastCounters) {
-                checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcastWithCounters", Object.class, Object.class, Object[].class, boolean.class, Counter.class));
-            } else {
-                checkcastSnippet = getRiMethod(CheckCastSnippets.class.getDeclaredMethod("checkcast", Object.class, Object.class, Object[].class, boolean.class));
-            }
-        } catch (NoSuchMethodException e) {
-            throw new GraalInternalError(e);
-        }
+        checkcasts = new CheckCastSnippets.Templates(this);
     }
 
 
@@ -416,31 +406,30 @@
             graph.replaceFixed(objectClassNode, memoryRead);
         } else if (n instanceof CheckCastNode) {
             if (shouldLowerCheckcast(graph)) {
-                final Map<CiConstant, CiConstant> hintHubsSet = new IdentityHashMap<>();
-                IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() {
-                    public boolean apply(CiConstant constant) {
-                        return hintHubsSet.containsKey(constant);
-                    }
-                };
                 CheckCastNode checkcast = (CheckCastNode) n;
                 ValueNode hub = checkcast.targetClassInstruction();
                 ValueNode object = checkcast.object();
                 TypeCheckHints hints = new TypeCheckHints(checkcast.targetClass(), checkcast.profile(), tool.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
-                StructuredGraph snippetGraph = (StructuredGraph) checkcastSnippet.compilerStorage().get(Graph.class);
-                assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed";
                 HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
                 for (int i = 0; i < hintHubs.length; i++) {
                     hintHubs[i] = ((HotSpotType) hints.types[i]).klassOop();
                 }
-                final CiConstant hintHubsConst = CiConstant.forObject(hintHubs);
-                hintHubsSet.put(hintHubsConst, hintHubsConst);
                 Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, checkcast, Arrays.toString(hints.types), hints.exact);
+
+                final Counter noHintsCounter;
                 if (GraalOptions.CheckcastCounters) {
-                    Counter noHintsCounter = checkcast.targetClass() == null ? Counter.noHints_unknown : checkcast.targetClass().isInterface() ? Counter.noHints_iface : Counter.noHints_class;
-                    InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact), CiConstant.forObject(noHintsCounter));
+                    if (checkcast.targetClass() == null) {
+                        noHintsCounter = Counter.noHints_unknown;
+                    } else if (checkcast.targetClass().isInterface()) {
+                        noHintsCounter = Counter.noHints_iface;
+                    } else {
+                        noHintsCounter = Counter.noHints_class;
+                    }
                 } else {
-                    InliningUtil.inlineSnippet(this, checkcast, checkcast, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
+                    noHintsCounter = null;
                 }
+                boolean checkNull = !object.stamp().nonNull();
+                checkcasts.get(hintHubs.length, hints.exact, checkNull, noHintsCounter).instantiate(this, checkcast, checkcast, hub, object, hintHubs, noHintsCounter);
                 new DeadCodeEliminationPhase().apply(graph);
             }
         } else {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Fri May 25 11:44:44 2012 +0200
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.hotspot.snippets;
 import static com.oracle.graal.hotspot.snippets.CheckCastSnippets.Counter.*;
+import static com.oracle.graal.snippets.SnippetTemplate.*;
 
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.*;
 
 import sun.misc.*;
 
@@ -33,6 +35,7 @@
 import com.oracle.graal.graph.Node.Fold;
 import com.oracle.graal.hotspot.*;
 import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.hotspot.ri.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
@@ -52,11 +55,12 @@
      * @param object the object whose type is being checked against {@code hub}
      * @param hintHubs the hubs of objects that have been profiled during previous executions
      * @param hintsAreExact specifies if {@code hintHubs} contains all subtypes of {@code hub}
+     * @param checkNull specifies if {@code object} may be null
      * @return {@code object} if the type check succeeds
      * @throws ClassCastException if the type check fails
      */
     @Snippet
-    public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) {
+    public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, boolean checkNull, @SuppressWarnings("unused") Counter ignore) {
         if (object == null) {
             return object;
         }
@@ -108,7 +112,7 @@
         /**
          * Increments this counter if counters are enabled. The body of this method has been carefully crafted
          * such that it contains no safepoints and no calls, neither of which are permissible in a snippet.
-         * Also, increments are not guaranteed to be atomic but that's acceptable for a counter like this.
+         * Also, increments are not guaranteed to be atomic which is acceptable for a counter.
          */
         void inc() {
             if (ENABLED) {
@@ -120,11 +124,8 @@
         static final boolean ENABLED = GraalOptions.CheckcastCounters;
     }
 
-    /**
-     * @see #checkcast(Object, Object, Object[], boolean)
-     */
     @Snippet
-    public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, Counter noHintsCounter) {
+    public static Object checkcastWithCounters(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact, @SuppressWarnings("unused") boolean checkNull, Counter noHintsCounter) {
         if (object == null) {
             isNull.inc();
             return object;
@@ -169,11 +170,6 @@
         return CompilerImpl.getInstance().getConfig().hubOffset;
     }
 
-    @Fold
-    private static boolean isInterface(RiResolvedType type) {
-        return type.isInterface();
-    }
-
     public static void printCounter(PrintStream out, Counter c, long total) {
         double percent = total == 0D ? 0D : ((double) (c.count * 100)) / total;
         out.println(String.format("%16s: %5.2f%%%10d  // %s", c.name(), percent, c.count, c.description));
@@ -208,4 +204,55 @@
             printCounter(out, c, total);
         }
     }
+
+    /**
+     * Templates for partially specialized checkcast snippet graphs.
+     */
+    public static class Templates {
+
+        private final ConcurrentHashMap<Integer, SnippetTemplate> templates;
+        private final RiResolvedMethod method;
+        private final RiRuntime runtime;
+
+        public Templates(RiRuntime runtime) {
+            this.runtime = runtime;
+            this.templates = new ConcurrentHashMap<>();
+            try {
+                Class[] parameterTypes = {Object.class, Object.class, Object[].class, boolean.class, boolean.class, Counter.class};
+                String name = GraalOptions.CheckcastCounters ? "checkcastWithCounters" : "checkcast";
+                method = runtime.getRiMethod(CheckCastSnippets.class.getDeclaredMethod(name, parameterTypes));
+            } catch (NoSuchMethodException e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        /**
+         * Gets a checkcast snippet specialized for a given set of inputs.
+         */
+        public SnippetTemplate get(int nHints, boolean isExact, boolean checkNull, Counter noHintsCounter) {
+            Integer key = key(nHints, isExact, checkNull);
+            SnippetTemplate result = templates.get(key);
+            if (result == null) {
+                HotSpotKlassOop[] hints = new HotSpotKlassOop[nHints];
+                Arrays.fill(hints, new HotSpotKlassOop(null, Templates.class));
+                result = SnippetTemplate.create(runtime, method, _, _, hints, isExact, checkNull, noHintsCounter);
+                templates.put(key, result);
+            }
+            return result;
+        }
+
+        /**
+         * Creates a canonical key for a combination of specialization parameters.
+         */
+        private static Integer key(int nHints, boolean isExact, boolean checkNull) {
+            int key = nHints << 2;
+            if (isExact) {
+                key |= 2;
+            }
+            if (checkNull) {
+                key |= 1;
+            }
+            return key;
+        }
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/ValueAnchorNode.java	Fri May 25 11:44:44 2012 +0200
@@ -44,8 +44,10 @@
         // Nothing to emit, since this node is used for structural purposes only.
     }
 
-    public void addAnchoredValue(ValueNode value) {
-        this.dependencies().add(value);
+    public void addAnchoredNode(ValueNode value) {
+        if (!this.dependencies().contains(value)) {
+            this.dependencies().add(value);
+        }
     }
 
     @Override
@@ -53,8 +55,8 @@
         if (this.predecessor() instanceof ValueAnchorNode) {
             // transfer values and remove
             ValueAnchorNode previousAnchor = (ValueAnchorNode) this.predecessor();
-            for (ValueNode node : dependencies().nonNull()) {
-                previousAnchor.dependencies().add(node);
+            for (ValueNode node : dependencies().nonNull().distinct()) {
+                previousAnchor.addAnchoredNode(node);
             }
             return null;
         }
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/CFGPrinterObserver.java	Fri May 25 11:44:44 2012 +0200
@@ -47,6 +47,7 @@
 
     private CFGPrinter cfgPrinter;
     private RiResolvedMethod curMethod;
+    private List<String> curDecorators = Collections.emptyList();
 
     @Override
     public void dump(Object object, String message) {
@@ -57,14 +58,37 @@
         }
     }
 
-    private static RiResolvedMethod lookupMethod() {
-        RiResolvedMethod method = Debug.contextLookup(RiResolvedMethod.class);
-        if (method != null) {
-            return method;
+    /**
+     * Looks for the outer most method and its {@link DebugDumpScope#decorator}s
+     * in the current debug scope and opens a new compilation scope if this pair
+     * does not match the current method and decorator pair.
+     */
+    private void checkMethodScope() {
+        RiResolvedMethod method = null;
+        ArrayList<String> decorators = new ArrayList<>();
+        for (Object o : Debug.context()) {
+            if (o instanceof RiResolvedMethod) {
+                method = (RiResolvedMethod) o;
+                decorators.clear();
+            } else if (o instanceof StructuredGraph) {
+                StructuredGraph graph = (StructuredGraph) o;
+                assert graph != null && graph.method() != null : "cannot find method context for CFG dump";
+                method = graph.method();
+                decorators.clear();
+            } else if (o instanceof DebugDumpScope) {
+                DebugDumpScope debugDumpScope = (DebugDumpScope) o;
+                if (debugDumpScope.decorator) {
+                    decorators.add(debugDumpScope.name);
+                }
+            }
         }
-        StructuredGraph graph = Debug.contextLookup(StructuredGraph.class);
-        assert graph != null && graph.method() != null : "cannot find method context for CFG dump";
-        return graph.method();
+
+        if (method != curMethod || !curDecorators.equals(decorators)) {
+            cfgPrinter.printCompilation(method);
+            TTY.println("CFGPrinter: Dumping method %s", method);
+            curMethod = method;
+            curDecorators = decorators;
+        }
     }
 
     public void dumpSandboxed(Object object, String message) {
@@ -84,13 +108,7 @@
             TTY.println("CFGPrinter: Output to file %s", file);
         }
 
-        RiResolvedMethod newMethod = lookupMethod();
-
-        if (newMethod != curMethod) {
-            cfgPrinter.printCompilation(newMethod);
-            TTY.println("CFGPrinter: Dumping method %s", newMethod);
-            curMethod = newMethod;
-        }
+        checkMethodScope();
 
         cfgPrinter.target = compiler.target;
         if (object instanceof LIR) {
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java	Fri May 25 11:44:44 2012 +0200
@@ -123,7 +123,7 @@
                 for (int i = 0; i < inlineContext.size(); ++i) {
                     if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
                         for (int j = i; j < inlineContext.size(); ++j) {
-                            openScope(inlineContext.get(j));
+                            openScope(inlineContext.get(j), j == 0);
                         }
                         break;
                     }
@@ -153,14 +153,19 @@
                 result.add(CiUtil.format("%H::%n(%p)", method));
             } else if (o instanceof DebugDumpScope) {
                 DebugDumpScope debugDumpScope = (DebugDumpScope) o;
-                result.add(debugDumpScope.getName());
+                if (debugDumpScope.decorator && !result.isEmpty()) {
+                    result.set(result.size() - 1, debugDumpScope.name + ":" + result.get(result.size() - 1));
+                } else {
+                    result.add(debugDumpScope.name);
+                }
             }
         }
         return result;
     }
 
-    private void openScope(String name) {
-        printer.beginGroup(Thread.currentThread().getName() + ":" + name, name, Debug.contextLookup(RiResolvedMethod.class), -1);
+    private void openScope(String name, boolean showThread) {
+        String prefix = showThread ? Thread.currentThread().getName() + ":" : "";
+        printer.beginGroup(prefix + name, name, Debug.contextLookup(RiResolvedMethod.class), -1);
     }
 
     private void closeScope() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Fri May 25 11:44:44 2012 +0200
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.snippets;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+import com.oracle.graal.compiler.loop.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+
+/**
+ * A snippet template is a graph created by parsing a snippet method and then
+ * specialized by binding constants to some of the snippet arguments and applying
+ * transformations such as canonicalization and loop peeling.
+ */
+public class SnippetTemplate {
+
+    /**
+     * Special value denoting a non-specialized argument.
+     */
+    public static final Object _ = new Object() {
+        @Override
+        public String toString() {
+            return "_";
+        }
+    };
+
+    /**
+     * Creates a snippet template.
+     *
+     * @param runtime
+     * @param method the snippet method to create the initial graph from
+     * @param args the arguments used to specialize the graph
+     */
+    public static SnippetTemplate create(final RiRuntime runtime, final RiResolvedMethod method, final Object... args) {
+        return Debug.scope("SnippetSpecialization", method, new Callable<SnippetTemplate>() {
+            @Override
+            public SnippetTemplate call() throws Exception {
+                assert Modifier.isStatic(method.accessFlags()) : "snippet method must be static: " + method;
+                RiSignature signature = method.signature();
+                assert signature.argumentCount(false) == args.length : "snippet method expects " + signature.argumentCount(false) + " arguments, " + args.length + " given";
+                StructuredGraph snippetGraph = (StructuredGraph) method.compilerStorage().get(Graph.class);
+
+                final Map<CiConstant, CiConstant> constantArrays = new IdentityHashMap<>();
+                IsImmutablePredicate immutabilityPredicate = new IsImmutablePredicate() {
+                    public boolean apply(CiConstant constant) {
+                        return constantArrays.containsKey(constant);
+                    }
+                };
+
+                // Copy snippet graph, replacing parameters with given args in the process
+                StructuredGraph snippetCopy = new StructuredGraph(snippetGraph.name, snippetGraph.method());
+                IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+                replacements.put(snippetGraph.start(), snippetCopy.start());
+                int localCount = 0;
+                for (LocalNode local : snippetGraph.getNodes(LocalNode.class)) {
+                    int index = local.index();
+                    Object arg = args[index];
+                    if (arg != _) {
+                        CiKind kind = signature.argumentKindAt(index, false);
+                        assert kind.isObject() || (arg != null && kind.toBoxedJavaClass() == arg.getClass()) :
+                            "arg " + index + " for " + method + " has wrong kind: expected " + kind + ", got " + (arg == null ? "null" : arg.getClass().getSimpleName());
+                        CiConstant specializationArg = CiConstant.forBoxed(kind, arg);
+                        if (kind.isObject()) {
+                            assert arg == null || signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().isInstance(arg) :
+                                String.format("argument %d is of wrong type: expected %s, got %s", index, signature.argumentTypeAt(index, method.holder()).resolve(method.holder()).toJava().getName(), arg.getClass().getName());
+                            if (arg != null) {
+                                if (arg.getClass().isArray()) {
+                                    constantArrays.put(specializationArg, specializationArg);
+                                }
+                            }
+                        }
+
+                        ConstantNode argNode = ConstantNode.forCiConstant(specializationArg, runtime, snippetCopy);
+                        replacements.put(local, argNode);
+                    }
+                    localCount++;
+                }
+                assert localCount == args.length : "snippet argument count mismatch";
+                snippetCopy.addDuplicates(snippetGraph.getNodes(), replacements);
+
+                Debug.dump(snippetCopy, "Before specialization");
+
+                if (!replacements.isEmpty()) {
+                    new CanonicalizerPhase(null, runtime, null, 0, immutabilityPredicate).apply(snippetCopy);
+                }
+
+                // Explode all loops in the snippet
+                if (snippetCopy.hasLoops()) {
+                    ControlFlowGraph cfg = ControlFlowGraph.compute(snippetCopy, true, true, false, false);
+                    for (Loop loop : cfg.getLoops()) {
+                        LoopBeginNode loopBegin = loop.loopBegin();
+                        SuperBlock wholeLoop = LoopTransformUtil.wholeLoop(loop);
+                        Debug.dump(snippetCopy, "Before exploding loop %s", loopBegin);
+                        int peel = 0;
+                        while (!loopBegin.isDeleted()) {
+                            int mark = snippetCopy.getMark();
+                            LoopTransformUtil.peel(loop, wholeLoop);
+                            Debug.dump(snippetCopy, "After peel %d", peel);
+                            new CanonicalizerPhase(null, runtime, null, mark, immutabilityPredicate).apply(snippetCopy);
+                            peel++;
+                        }
+                        Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
+                    }
+                }
+
+                // Remove all frame states from inlined snippet graph. Snippets must be atomic (i.e. free
+                // of side-effects that prevent deoptimizing to a point before the snippet).
+                for (Node node : snippetCopy.getNodes()) {
+                    if (node instanceof StateSplit) {
+                        StateSplit stateSplit = (StateSplit) node;
+                        FrameState frameState = stateSplit.stateAfter();
+                        assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node + "\n    " + frameState.toString(Verbosity.Debugger);
+                        if (frameState != null) {
+                            stateSplit.setStateAfter(null);
+                        }
+                    }
+                }
+
+                new DeadCodeEliminationPhase().apply(snippetCopy);
+                return new SnippetTemplate(args, snippetCopy);
+            }
+        });
+    }
+
+    SnippetTemplate(Object[] args, StructuredGraph graph) {
+        Object[] flattenedArgs = flatten(args);
+        this.graph = graph;
+        this.parameters = new Object[flattenedArgs.length];
+
+        // Find the constant nodes corresponding to the flattened positional parameters
+        for (ConstantNode node : graph.getNodes().filter(ConstantNode.class)) {
+            if (node.kind().isObject()) {
+                CiConstant constant = node.asConstant();
+                if (constant.kind.isObject() && !constant.isNull()) {
+                    for (int i = 0; i < flattenedArgs.length; i++) {
+                        if (flattenedArgs[i] == constant.asObject()) {
+                            parameters[i] = node;
+                        }
+                    }
+                }
+            }
+        }
+
+        // Find the local nodes corresponding to the flattened positional parameters
+        int localIndex = 0;
+        for (int i = 0; i < flattenedArgs.length; i++) {
+            if (flattenedArgs[i] == _) {
+                for (LocalNode local : graph.getNodes(LocalNode.class)) {
+                    if (local.index() == localIndex) {
+                        assert parameters[i] == null;
+                        parameters[i] = local;
+                    }
+                }
+                localIndex++;
+            } else {
+                Object param = parameters[i];
+                if (param == null) {
+                    parameters[i] = flattenedArgs[i];
+                } else {
+                    assert param instanceof ConstantNode;
+                    assert ((ConstantNode) param).kind().isObject();
+                }
+            }
+        }
+
+        nodes = new ArrayList<>(graph.getNodeCount());
+        ReturnNode retNode = null;
+        StartNode entryPointNode = graph.start();
+        for (Node node : graph.getNodes()) {
+            if (node == entryPointNode || node == entryPointNode.stateAfter()) {
+                // Do nothing.
+            } else {
+                nodes.add(node);
+                if (node instanceof ReturnNode) {
+                    retNode = (ReturnNode) node;
+                }
+            }
+        }
+        this.returnNode = retNode;
+    }
+
+    /**
+     * The graph built from the snippet method.
+     */
+    public final StructuredGraph graph;
+
+    /**
+     * The flattened positional parameters of this snippet.
+     * A {@link LocalNode} element is bound to a {@link ValueNode} to be supplied during
+     * instantiation, a {@link ConstantNode} is replaced by an object constant and any
+     * other element denotes an input fixed during specialization.
+     */
+    public final Object[] parameters;
+
+    /**
+     * The return node (if any) of the snippet.
+     */
+    public final ReturnNode returnNode;
+
+    /**
+     * The nodes to be inlined when this specialization is instantiated.
+     */
+    public final ArrayList<Node> nodes;
+
+    private IdentityHashMap<Node, Node> replacements(StructuredGraph replaceeGraph, RiRuntime runtime, Object... args) {
+        Object[] flattenedArgs = flatten(args);
+        IdentityHashMap<Node, Node> replacements = new IdentityHashMap<>();
+        assert parameters.length >= flattenedArgs.length;
+        for (int i = 0; i < flattenedArgs.length; i++) {
+            Object param = parameters[i];
+            Object arg = flattenedArgs[i];
+            if (arg == null) {
+                assert !(param instanceof ValueNode) : param;
+            } else if (arg instanceof ValueNode) {
+                assert param instanceof LocalNode;
+                replacements.put((LocalNode) param, (ValueNode) arg);
+            } else {
+                replacements.put((ConstantNode) param, ConstantNode.forObject(arg, runtime, replaceeGraph));
+            }
+        }
+        return replacements;
+    }
+
+    /**
+     * Replaces a given node with this specialized snippet.
+     *
+     * @param runtime
+     * @param replacee the node that will be replaced
+     * @param anchor the control flow replacee
+     * @param args the arguments to be bound to the flattened positional parameters of the snippet
+     */
+    public void instantiate(RiRuntime runtime,
+                    Node replacee,
+                    FixedWithNextNode anchor, Object... args) {
+
+        // Inline the snippet nodes, replacing parameters with the given args in the process
+        String name = graph.name == null ? "{copy}" : graph.name + "{copy}";
+        StructuredGraph graphCopy = new StructuredGraph(name, graph.method());
+        StartNode entryPointNode = graph.start();
+        FixedNode firstCFGNode = entryPointNode.next();
+        StructuredGraph replaceeGraph = (StructuredGraph) replacee.graph();
+        IdentityHashMap<Node, Node> replacements = replacements(replaceeGraph, runtime, args);
+        Map<Node, Node> duplicates = replaceeGraph.addDuplicates(nodes, replacements);
+        Debug.dump(replaceeGraph, "After inlining snippet %s", graphCopy.method());
+
+        // Re-wire the control flow graph around the replacee
+        FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+        anchor.replaceAtPredecessors(firstCFGNodeDuplicate);
+        FixedNode next = anchor.next();
+        anchor.setNext(null);
+
+        // Replace all usages of the replacee with the value returned by the snippet
+        Node returnValue = null;
+        if (returnNode != null) {
+            if (returnNode.result() instanceof LocalNode) {
+                returnValue = replacements.get(returnNode.result());
+            } else {
+                returnValue = duplicates.get(returnNode.result());
+            }
+            assert returnValue != null || replacee.usages().isEmpty();
+            replacee.replaceAtUsages(returnValue);
+
+            Node returnDuplicate = duplicates.get(returnNode);
+            returnDuplicate.clearInputs();
+            returnDuplicate.replaceAndDelete(next);
+        }
+
+        // Remove the replacee from its graph
+        replacee.clearInputs();
+        replacee.replaceAtUsages(null);
+        if (replacee instanceof FixedNode) {
+            GraphUtil.killCFG((FixedNode) replacee);
+        } else {
+            replacee.safeDelete();
+        }
+
+        Debug.dump(replaceeGraph, "After lowering %s with %s", replacee, this);
+    }
+
+    /**
+     * Flattens a list of objects by replacing any array in {@code args} with its elements.
+     */
+    private static Object[] flatten(Object... args) {
+        List<Object> list = new ArrayList<>(args.length * 2);
+        for (Object o : args) {
+            if (o instanceof Object[]) {
+                list.addAll(Arrays.asList((Object[]) o));
+            } else {
+                list.add(o);
+            }
+        }
+        return list.toArray(new Object[list.size()]);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(graph.toString()).append('(');
+        for (int i = 0; i < parameters.length; i++) {
+            Object param = parameters[i];
+            if (param instanceof ConstantNode) {
+                buf.append(((ConstantNode) param).asConstant().asObject());
+            } else if (param instanceof LocalNode) {
+                buf.append('_');
+            } else {
+                buf.append(param);
+            }
+            if (i != parameters.length - 1) {
+                buf.append(", ");
+            }
+        }
+        return buf.append(')').toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CheckCastTest.java	Fri May 25 11:44:44 2012 +0200
@@ -0,0 +1,121 @@
+/*
+ * 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.compiler.tests;
+
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.max.cri.ri.*;
+
+/**
+ * Tests the implementation of checkcast, allowing profiling information to
+ * be manually specified.
+ */
+public class CheckCastTest extends TypeCheckTest {
+
+    @Override
+    protected void replaceProfile(StructuredGraph graph, RiTypeProfile profile) {
+        CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
+        if (ccn != null) {
+            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile));
+            graph.replaceFixedWithFixed(ccn, ccnNew);
+        }
+    }
+
+    @Test
+    public void test1() {
+        test("asNumber",    profile(),                        111);
+        test("asNumber",    profile(Integer.class),           111);
+        test("asNumber",    profile(Long.class, Short.class), 111);
+        test("asNumberExt", profile(),                        111);
+        test("asNumberExt", profile(Integer.class),           111);
+        test("asNumberExt", profile(Long.class, Short.class), 111);
+    }
+
+    @Test
+    public void test2() {
+        test("asString",    profile(),             "111");
+        test("asString",    profile(String.class), "111");
+        test("asString",    profile(String.class), "111");
+
+        final String nullString = null;
+        test("asString",    profile(),             nullString);
+        test("asString",    profile(String.class), nullString);
+        test("asString",    profile(String.class), nullString);
+
+        test("asStringExt", profile(),             "111");
+        test("asStringExt", profile(String.class), "111");
+        test("asStringExt", profile(String.class), "111");
+    }
+
+    @Test
+    public void test3() {
+        test("asNumber", profile(), "111");
+    }
+
+    @Test
+    public void test4() {
+        test("asString", profile(String.class), 111);
+    }
+
+    @Test
+    public void test5() {
+        test("asNumberExt", profile(), "111");
+    }
+
+    @Test
+    public void test6() {
+        test("asStringExt", profile(String.class), 111);
+    }
+
+    public static Number asNumber(Object o) {
+        return (Number) o;
+    }
+
+    public static String asString(Object o) {
+        return (String) o;
+    }
+
+    public static Number asNumberExt(Object o) {
+        Number n = (Number) o;
+        return n.intValue() + 10;
+    }
+
+    public static String asStringExt(Object o) {
+        String s = (String) o;
+        return "#" + s;
+    }
+
+    @Test
+    public void test7() {
+        test("arrayFill", profile(), new Object[100], "111");
+    }
+
+    public static Object[] arrayFill(Object[] arr, Object value) {
+        for (int i = 0; i < arr.length; i++) {
+            arr[i] = value;
+        }
+        return arr;
+    }
+}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Fri May 25 11:44:44 2012 +0200
@@ -68,8 +68,7 @@
         }
 
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
-        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
+        RiCompiledMethod compiledMethod = compile(riMethod, graph);
         try {
             Object result = compiledMethod.execute("1", "2", "3");
             Assert.assertEquals("1-2-3", result);
@@ -83,8 +82,7 @@
         Method method = getMethod("testMethod");
         final StructuredGraph graph = parse(method);
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
-        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
+        RiCompiledMethod compiledMethod = compile(riMethod, graph);
         try {
             Object result = compiledMethod.executeVarargs("1", "2", "3");
             Assert.assertEquals("1 2 3", result);
@@ -98,8 +96,7 @@
         Method method = getMethod("testMethodVirtual");
         final StructuredGraph graph = parse(method);
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
-        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
+        RiCompiledMethod compiledMethod = compile(riMethod, graph);
         try {
             f1 = "0";
             Object result = compiledMethod.executeVarargs(this, "1", "2", "3");
@@ -127,9 +124,7 @@
             }
         }
 
-        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        final RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
-
+        RiCompiledMethod compiledMethod = compile(riMethod, graph);
         final CompilableObject compilableObject = new CompilableObjectImpl(0);
 
         Object result;
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Fri May 25 11:44:44 2012 +0200
@@ -146,6 +146,17 @@
         }
     }
 
+    private static int compilationId = 0;
+
+    protected RiCompiledMethod compile(final RiResolvedMethod method, final StructuredGraph graph) {
+        return Debug.scope("Compiling", new DebugDumpScope(String.valueOf(compilationId++), true), new Callable<RiCompiledMethod>() {
+            public RiCompiledMethod call() throws Exception {
+                CiTargetMethod targetMethod = runtime.compile(method, graph);
+                return addMethod(method, targetMethod);
+            }
+        });
+    }
+
     protected RiCompiledMethod addMethod(final RiResolvedMethod method, final CiTargetMethod tm) {
         Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable<RiCompiledMethod>() {
             @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/InstanceOfTest.java	Fri May 25 11:44:44 2012 +0200
@@ -0,0 +1,146 @@
+/*
+ * 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.compiler.tests;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.max.cri.ri.*;
+
+/**
+ * Tests the implementation of instanceof, allowing profiling information to
+ * be manually specified.
+ */
+public class InstanceOfTest extends TypeCheckTest {
+
+    @Override
+    protected void replaceProfile(StructuredGraph graph, RiTypeProfile profile) {
+        InstanceOfNode ion = graph.getNodes().filter(InstanceOfNode.class).first();
+        if (ion != null) {
+            InstanceOfNode ionNew = graph.add(new InstanceOfNode(ion.targetClassInstruction(), ion.targetClass(), ion.object(), profile));
+            graph.replaceFloating(ion, ionNew);
+        }
+    }
+
+    @Test
+    public void test1() {
+        test("isString",    profile(),                        "object");
+        test("isString",    profile(String.class),            "object");
+
+        test("isString",    profile(),                        Object.class);
+        test("isString",    profile(String.class),            Object.class);
+    }
+
+    @Test
+    public void test2() {
+        test("isStringInt",    profile(),                        "object");
+        test("isStringInt",    profile(String.class),            "object");
+
+        test("isStringInt",    profile(),                        Object.class);
+        test("isStringInt",    profile(String.class),            Object.class);
+    }
+
+    @Test
+    public void test3() {
+        Throwable throwable = new Exception();
+        test("isThrowable",    profile(),                             throwable);
+        test("isThrowable",    profile(Throwable.class),              throwable);
+        test("isThrowable",    profile(Exception.class, Error.class), throwable);
+
+        test("isThrowable",    profile(),                             Object.class);
+        test("isThrowable",    profile(Throwable.class),              Object.class);
+        test("isThrowable",    profile(Exception.class, Error.class), Object.class);
+    }
+
+    @Test
+    public void test4() {
+        Throwable throwable = new Exception();
+        test("isThrowableInt",    profile(),                             throwable);
+        test("isThrowableInt",    profile(Throwable.class),              throwable);
+        test("isThrowableInt",    profile(Exception.class, Error.class), throwable);
+
+        test("isThrowableInt",    profile(),                             Object.class);
+        test("isThrowableInt",    profile(Throwable.class),              Object.class);
+        test("isThrowableInt",    profile(Exception.class, Error.class), Object.class);
+    }
+
+    @Test
+    public void test5() {
+        Map map = new HashMap<>();
+        test("isMap",    profile(),                             map);
+        test("isMap",    profile(HashMap.class),                map);
+        test("isMap",    profile(TreeMap.class, HashMap.class), map);
+
+        test("isMap",    profile(),                             Object.class);
+        test("isMap",    profile(HashMap.class),                Object.class);
+        test("isMap",    profile(TreeMap.class, HashMap.class), Object.class);
+    }
+
+    @Test
+    public void test6() {
+        Map map = new HashMap<>();
+        test("isMapInt",    profile(),                             map);
+        test("isMapInt",    profile(HashMap.class),                map);
+        test("isMapInt",    profile(TreeMap.class, HashMap.class), map);
+
+        test("isMapInt",    profile(),                             Object.class);
+        test("isMapInt",    profile(HashMap.class),                Object.class);
+        test("isMapInt",    profile(TreeMap.class, HashMap.class), Object.class);
+    }
+
+    public static boolean isString(Object o) {
+        return o instanceof String;
+    }
+
+    public static int isStringInt(Object o) {
+        if (o instanceof String) {
+            return 1;
+        }
+        return 0;
+    }
+
+    public static boolean isThrowable(Object o) {
+        return o instanceof Throwable;
+    }
+
+    public static int isThrowableInt(Object o) {
+        if (o instanceof Throwable) {
+            return 1;
+        }
+        return 0;
+    }
+
+    public static boolean isMap(Object o) {
+        return o instanceof Map;
+    }
+
+    public static int isMapInt(Object o) {
+        if (o instanceof Map) {
+            return 1;
+        }
+        return 0;
+    }
+}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Fri May 25 11:35:18 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,165 +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.compiler.tests;
-
-import java.lang.reflect.*;
-
-import org.junit.*;
-
-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.cri.ri.RiTypeProfile.ProfiledType;
-
-public class LowerCheckCastTest extends GraphTest {
-
-    private RiCompiledMethod compile(Method method, RiTypeProfile profile) {
-        final StructuredGraph graph = parse(method);
-
-        CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
-        if (ccn != null) {
-            CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile));
-            graph.replaceFixedWithFixed(ccn, ccnNew);
-        }
-
-        final RiResolvedMethod riMethod = runtime.getRiMethod(method);
-        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        return addMethod(riMethod, targetMethod);
-    }
-
-    private RiTypeProfile profile(Class... types) {
-        if (types.length == 0) {
-            return null;
-        }
-        ProfiledType[] ptypes = new ProfiledType[types.length];
-        for (int i = 0; i < types.length; i++) {
-            ptypes[i] = new ProfiledType(runtime.getType(types[i]), 1.0D / types.length);
-        }
-        return new RiTypeProfile(0.0D, ptypes);
-    }
-
-    private void test(String name, RiTypeProfile profile, Object... args) {
-        Method method = getMethod(name);
-        Object expect = null;
-        Throwable exception = null;
-        try {
-            // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved
-            expect = method.invoke(null, args);
-        } catch (InvocationTargetException e) {
-            exception = e.getTargetException();
-        } catch (Exception e) {
-            throw new RuntimeException(e);
-        }
-        RiCompiledMethod compiledMethod = compile(method, profile);
-        compiledMethod.method();
-
-        if (exception != null) {
-            try {
-                compiledMethod.executeVarargs(args);
-                Assert.fail("expected " + exception);
-            } catch (Throwable e) {
-                Assert.assertEquals(exception.getClass(), e.getClass());
-            }
-        } else {
-            Object actual = compiledMethod.executeVarargs(args);
-            Assert.assertEquals(expect, actual);
-        }
-    }
-
-    @Test
-    public void test1() {
-        test("asNumber",    profile(),                        111);
-        test("asNumber",    profile(Integer.class),           111);
-        test("asNumber",    profile(Long.class, Short.class), 111);
-        test("asNumberExt", profile(),                        111);
-        test("asNumberExt", profile(Integer.class),           111);
-        test("asNumberExt", profile(Long.class, Short.class), 111);
-    }
-
-    @Test
-    public void test2() {
-        test("asString",    profile(),             "111");
-        test("asString",    profile(String.class), "111");
-        test("asString",    profile(String.class), "111");
-
-        final String nullString = null;
-        test("asString",    profile(),             nullString);
-        test("asString",    profile(String.class), nullString);
-        test("asString",    profile(String.class), nullString);
-
-        test("asStringExt", profile(),             "111");
-        test("asStringExt", profile(String.class), "111");
-        test("asStringExt", profile(String.class), "111");
-    }
-
-    @Test
-    public void test3() {
-        test("asNumber", profile(), "111");
-    }
-
-    @Test
-    public void test4() {
-        test("asString", profile(String.class), 111);
-    }
-
-    @Test
-    public void test5() {
-        test("asNumberExt", profile(), "111");
-    }
-
-    @Test
-    public void test6() {
-        test("asStringExt", profile(String.class), 111);
-    }
-
-    public static Number asNumber(Object o) {
-        return (Number) o;
-    }
-
-    public static String asString(Object o) {
-        return (String) o;
-    }
-
-    public static Number asNumberExt(Object o) {
-        Number n = (Number) o;
-        return n.intValue() + 10;
-    }
-
-    public static String asStringExt(Object o) {
-        String s = (String) o;
-        return "#" + s;
-    }
-
-    @Test
-    public void test7() {
-        test("arrayFill", profile(), new Object[100], "111");
-    }
-
-    public static Object[] arrayFill(Object[] arr, Object value) {
-        for (int i = 0; i < arr.length; i++) {
-            arr[i] = value;
-        }
-        return arr;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeCheckTest.java	Fri May 25 11:44:44 2012 +0200
@@ -0,0 +1,84 @@
+/*
+ * 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.compiler.tests;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.cri.ri.RiTypeProfile.ProfiledType;
+
+/**
+ * Base class for checkcast and instanceof test classes.
+ */
+public abstract class TypeCheckTest extends GraphTest {
+
+    protected abstract void replaceProfile(StructuredGraph graph, RiTypeProfile profile);
+
+    private RiCompiledMethod compile(Method method, RiTypeProfile profile) {
+        final StructuredGraph graph = parse(method);
+        replaceProfile(graph, profile);
+        return compile(runtime.getRiMethod(method), graph);
+    }
+
+    protected RiTypeProfile profile(Class... types) {
+        if (types.length == 0) {
+            return null;
+        }
+        ProfiledType[] ptypes = new ProfiledType[types.length];
+        for (int i = 0; i < types.length; i++) {
+            ptypes[i] = new ProfiledType(runtime.getType(types[i]), 1.0D / types.length);
+        }
+        return new RiTypeProfile(0.0D, ptypes);
+    }
+
+    protected void test(String name, RiTypeProfile profile, Object... args) {
+        Method method = getMethod(name);
+        Object expect = null;
+        Throwable exception = null;
+        try {
+            // This gives us both the expected return value as well as ensuring that the method to be compiled is fully resolved
+            expect = method.invoke(null, args);
+        } catch (InvocationTargetException e) {
+            exception = e.getTargetException();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        RiCompiledMethod compiledMethod = compile(method, profile);
+        compiledMethod.method();
+
+        if (exception != null) {
+            try {
+                compiledMethod.executeVarargs(args);
+                Assert.fail("expected " + exception);
+            } catch (Throwable e) {
+                Assert.assertEquals(exception.getClass(), e.getClass());
+            }
+        } else {
+            Object actual = compiledMethod.executeVarargs(args);
+            Assert.assertEquals(expect, actual);
+        }
+    }
+}
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java	Fri May 25 11:35:18 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiConstant.java	Fri May 25 11:44:44 2012 +0200
@@ -473,6 +473,8 @@
      */
     public static CiConstant forBoxed(CiKind kind, Object value) {
         switch (kind) {
+            case Boolean:
+                return forBoolean((Boolean) value);
             case Byte:
                 return forByte((Byte) value);
             case Char:
--- a/mx/commands.py	Fri May 25 11:35:18 2012 +0200
+++ b/mx/commands.py	Fri May 25 11:44:44 2012 +0200
@@ -736,6 +736,10 @@
 
     args = parser.parse_args(args)
 
+    global _vmbuild
+    global _vm
+    global _jacoco
+    
     tasks = []             
     total = Task('Gate')
     try:
@@ -752,9 +756,7 @@
         t = Task('BuildJava')
         build(['--no-native'])
         tasks.append(t.stop())
-        global _jacoco
         for vmbuild in ['fastdebug', 'product']:
-            global _vmbuild
             _vmbuild = vmbuild
             
             if args.buildNative:
@@ -816,6 +818,15 @@
             t = Task('BuildHotSpotVarieties')
             buildvms(['--vms', 'client,server', '--builds', 'fastdebug,product'])
             tasks.append(t.stop())
+
+            for vmbuild in ['product', 'fastdebug']:
+                _vmbuild = vmbuild
+                for theVm in ['client', 'server']:
+                    _vm = theVm
+
+                    t = Task('DaCapo_pmd:' + theVm + ':' + vmbuild)
+                    dacapo(['pmd'])
+                    tasks.append(t.stop())
         
     except KeyboardInterrupt:
         total.abort(1)
--- a/src/share/vm/runtime/vframeArray.cpp	Fri May 25 11:35:18 2012 +0200
+++ b/src/share/vm/runtime/vframeArray.cpp	Fri May 25 11:44:44 2012 +0200
@@ -252,7 +252,9 @@
       case Deoptimization::Unpack_uncommon_trap:
       case Deoptimization::Unpack_reexecute:
         // redo last byte code
+#ifdef GRAAL
         assert(should_reexecute(), "");
+#endif
         pc  = Interpreter::deopt_entry(vtos, 0);
         use_next_mdp = false;
         break;