changeset 5384:c7f92c6246ba

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 09 May 2012 12:11:36 +0200
parents 1436de7b7cab (current diff) 67e63e8dcbd2 (diff)
children 31ec401eb592
files graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalRuntimeAccess.java
diffstat 61 files changed, 951 insertions(+), 293 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/InsertStateAfterPlaceholderPhase.java	Wed May 09 12:11:36 2012 +0200
@@ -29,7 +29,7 @@
 
 public class InsertStateAfterPlaceholderPhase extends Phase {
 
-    private static class PlaceholderNode extends AbstractStateSplit implements Node.IterableNodeType, LIRLowerable {
+    private static class PlaceholderNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType, LIRLowerable {
         public PlaceholderNode() {
             super(StampFactory.illegal());
         }
@@ -38,6 +38,11 @@
         public void generate(LIRGeneratorTool gen) {
             // nothing to do
         }
+
+        @Override
+        public boolean hasSideEffect() {
+            return false;
+        }
     }
 
     @Override
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/LIRGenLowerable.java	Wed May 09 12:11:36 2012 +0200
@@ -23,7 +23,13 @@
 package com.oracle.graal.compiler.target;
 
 import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.lir.*;
+import com.oracle.graal.nodes.spi.*;
 
+/**
+ * An alternative to {@link LIRLowerable} for lowering that is tightly coupled
+ * to {@link LIRGenerator} and {@link LIRInstruction}.
+ */
 public interface LIRGenLowerable {
 
     void generate(LIRGenerator generator);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/InliningUtil.java	Wed May 09 12:11:36 2012 +0200
@@ -27,10 +27,13 @@
 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.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.PhiNode.PhiType;
 import com.oracle.graal.nodes.calc.*;
@@ -766,10 +769,10 @@
 
     /**
      * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+     *
      * @param invoke the invoke that will be replaced
      * @param inlineGraph the graph that the invoke will be replaced with
      * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
-     * @return The node that represents the return value, or null for void methods and methods that have no non-exceptional exit.
      */
     public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
         NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
@@ -903,6 +906,150 @@
         }
     }
 
+    /**
+     * 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) {
+        // 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, false, 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);
+                while (!loopBegin.isDeleted()) {
+                    snippetCopy.mark();
+                    LoopTransformUtil.peel(loop, wholeLoop);
+                    new CanonicalizerPhase(null, runtime, null, true, immutabilityPredicate).apply(snippetCopy);
+                }
+                Debug.dump(snippetCopy, "After exploding loop %s", loopBegin);
+            }
+        }
+
+        // Gather the nodes in the snippets that are to be inlined
+        ArrayList<Node> nodes = new ArrayList<>();
+        ReturnNode returnNode = null;
+        BeginNode 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();
+        Map<Node, Node> duplicates = graph.addDuplicates(nodes, replacements);
+
+        // 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 (node instanceof StateSplit) {
+                StateSplit stateSplit = (StateSplit) node;
+                FrameState frameState = stateSplit.stateAfter();
+                assert !stateSplit.hasSideEffect() : "snippets cannot contain side-effecting node " + node;
+                if (frameState != null) {
+                    stateSplit.setStateAfter(null);
+                }
+            }
+        }
+
+        // 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.graph/src/com/oracle/graal/graph/Graph.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed May 09 12:11:36 2012 +0200
@@ -34,7 +34,7 @@
  */
 public class Graph {
 
-    protected final String name;
+    public final String name;
 
     private static final boolean TIME_TRAVEL = false;
 
@@ -220,6 +220,9 @@
         return true;
     }
 
+    /**
+     * @see #getNewNodes()
+     */
     public void mark() {
         this.mark = nodeIdCount();
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed May 09 12:11:36 2012 +0200
@@ -555,6 +555,8 @@
             if (type.isPrimitive()) {
                 if (type == Integer.TYPE) {
                     value = unsafe.getInt(node, dataOffsets[i]);
+                } else if (type == Long.TYPE) {
+                    value = unsafe.getLong(node, dataOffsets[i]);
                 } else if (type == Boolean.TYPE) {
                     value = unsafe.getBoolean(node, dataOffsets[i]);
                 } else if (type == Long.TYPE) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java	Wed May 09 12:11:36 2012 +0200
@@ -153,10 +153,10 @@
         Debug.scope("CodeInstall", new Object[] {compiler.getCompiler(), method}, new Runnable() {
             @Override
             public void run() {
-                final HotSpotCodeInfo info = Debug.isDumpEnabled() ? new HotSpotCodeInfo(compiler, tm, method) : null;
+                final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null;
                 compiler.getRuntime().installMethod(method, tm, info);
                 if (info != null) {
-                    Debug.dump(info, "After code installation");
+                    Debug.dump(info[0], "After code installation");
                 }
             }
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerImpl.java	Wed May 09 12:11:36 2012 +0200
@@ -157,12 +157,19 @@
     }
 
     /**
-     * Factory method for getting a Graal compiler instance. This method is called via reflection.
+     * Factory method for getting a {@link GraalRuntime} instance. This method is called via reflection.
      */
     public static GraalRuntime getGraalRuntime() {
         return getInstance().getRuntime();
     }
 
+    /**
+     * Factory method for getting a {@link GraalCompiler} instance. This method is called via reflection.
+     */
+    public static GraalCompiler getGraalCompiler() {
+        return getInstance().getCompiler();
+    }
+
     @Override
     public GraalCompiler getCompiler() {
         if (compiler == null) {
@@ -238,19 +245,6 @@
     @Override
     public HotSpotRuntime getRuntime() {
         if (runtime == null) {
-            if (GraalOptions.PrintCFGToFile) {
-//                context.addCompilationObserver(new CFGPrinterObserver());
-            }
-           // if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) {
-             //   CompilationObserver observer;
-               // if (GraalOptions.PrintIdealGraphFile) {
-              //      observer = new IdealGraphPrinterObserver();
-              //  } else {
-              //      observer = new IdealGraphPrinterObserver(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort);
-              //  }
-//                context.addCompilationObserver(observer);
-                // TODO (thomaswue): Install observer.
-           // }
             runtime = new HotSpotRuntime(config, this);
         }
         return runtime;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilerObject.java	Wed May 09 12:11:36 2012 +0200
@@ -24,11 +24,13 @@
 
 import java.io.*;
 
+import com.oracle.max.cri.ci.CiKind.FormatWithToString;
+
 
 /**
  * Parent class for all HotSpot Ri... types.
  */
-public abstract class CompilerObject implements Serializable {
+public abstract class CompilerObject implements Serializable, FormatWithToString {
     private static final long serialVersionUID = -4551670987101214877L;
     protected final Compiler compiler;
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Wed May 09 12:11:36 2012 +0200
@@ -60,7 +60,7 @@
 
         // Report the filters that have been configured so the user can verify it's what they expect
         if (logFilter != null || meterFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) {
-            TTY.println(this.toString());
+            TTY.println(Thread.currentThread().getName() + ": " + toString());
         }
 
         if (GraalOptions.PrintIdealGraphFile) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Wed May 09 12:11:36 2012 +0200
@@ -63,7 +63,7 @@
 
     void RiConstantPool_loadReferencedType(HotSpotTypeResolved pool, int cpi, byte byteCode);
 
-    HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean installCode, HotSpotCodeInfo info);
+    HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean makeDefault, HotSpotCodeInfo info);
 
     long installStub(HotSpotTargetMethod targetMethod, HotSpotCodeInfo info);
 
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Wed May 09 12:11:36 2012 +0200
@@ -78,7 +78,7 @@
     public native RiField RiConstantPool_lookupField(HotSpotTypeResolved pool, int cpi, byte byteCode);
 
     @Override
-    public native HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean installCode, HotSpotCodeInfo info);
+    public native HotSpotCompiledMethod installMethod(HotSpotTargetMethod targetMethod, boolean makeDefault, HotSpotCodeInfo info);
 
     @Override
     public native long installStub(HotSpotTargetMethod targetMethod, HotSpotCodeInfo info);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed May 09 12:11:36 2012 +0200
@@ -53,6 +53,7 @@
 
     private final Compiler compiler;
     private IntrinsifyArrayCopyPhase intrinsifyArrayCopy;
+    private LowerCheckCastPhase lowerCheckCastPhase;
 
     public final HotSpotTypePrimitive typeBoolean;
     public final HotSpotTypePrimitive typeChar;
@@ -115,10 +116,12 @@
                 @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());
                 }
             });
 
@@ -157,6 +160,8 @@
         }
     }
 
+
+
     /**
      * This method is the first method compiled during bootstrapping. Put any code in there that warms up compiler paths
      * that are otherwise not exercised during bootstrapping and lead to later deoptimization when application code is
@@ -483,6 +488,7 @@
         if (GraalOptions.Intrinsify) {
             phasePlan.addPhase(PhasePosition.HIGH_LEVEL, intrinsifyArrayCopy);
         }
+        phasePlan.addPhase(PhasePosition.HIGH_LEVEL, lowerCheckCastPhase);
         return phasePlan;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/nodes/TypeCheckSlowPath.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,71 @@
+/*
+ * 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.hotspot.nodes;
+
+import com.oracle.graal.compiler.gen.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.hotspot.target.amd64.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.max.cri.ci.*;
+
+/**
+ * A node for calling the HotSpot stub implementing the slow path of a type check.
+ * This stub does not use any registers.
+ */
+public final class TypeCheckSlowPath extends FloatingNode implements LIRGenLowerable {
+
+    @Input private ValueNode objectHub;
+    @Input private ValueNode hub;
+
+    public ValueNode objectHub() {
+        return objectHub;
+    }
+
+    public ValueNode hub() {
+        return hub;
+    }
+
+    public TypeCheckSlowPath(ValueNode objectHub, ValueNode hub) {
+        super(StampFactory.forKind(CiKind.Object));
+        this.objectHub = objectHub;
+        this.hub = hub;
+    }
+
+    @Override
+    public void generate(LIRGenerator gen) {
+        CiValue objectHubOpr = gen.operand(objectHub);
+        AMD64TypeCheckSlowPathOp op = new AMD64TypeCheckSlowPathOp(objectHubOpr, gen.operand(hub));
+        gen.append(op);
+        gen.setResult(this, objectHubOpr);
+    }
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static Object check(Object objectHub, Object hub) {
+        throw new UnsupportedOperationException("This method may only be compiled with the Graal compiler");
+    }
+
+
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotKlassOop.java	Wed May 09 12:11:36 2012 +0200
@@ -44,4 +44,9 @@
         super(compiler);
         this.javaMirror = javaMirror;
     }
+
+    @Override
+    public String toString() {
+        return "HotSpotKlassOop<" + javaMirror.getName() + ">";
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Wed May 09 12:11:36 2012 +0200
@@ -475,14 +475,25 @@
         return (RiResolvedMethod) compiler.getCompilerToVM().getRiMethod(reflectionMethod);
     }
 
-    @Override
-    public void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo info) {
-        compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), true, (HotSpotCodeInfo) info);
+    private HotSpotCodeInfo makeInfo(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info) {
+        HotSpotCodeInfo hsInfo = null;
+        if (info != null && info.length > 0) {
+            hsInfo = new HotSpotCodeInfo(compiler, code, (HotSpotMethodResolved) method);
+            info[0] = hsInfo;
+        }
+        return hsInfo;
     }
 
     @Override
-    public RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code) {
-        return compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), false, null);
+    public void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info) {
+        HotSpotCodeInfo hsInfo = makeInfo(method, code, info);
+        compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), true, hsInfo);
+    }
+
+    @Override
+    public RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info) {
+        HotSpotCodeInfo hsInfo = makeInfo(method, code, info);
+        return compiler.getCompilerToVM().installMethod(new HotSpotTargetMethod(compiler, (HotSpotMethodResolved) method, code), false, hsInfo);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/CheckCastSnippets.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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 com.oracle.graal.graph.Node.Fold;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.nodes.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.snippets.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+
+
+public class CheckCastSnippets implements SnippetsInterface {
+
+    @Snippet
+    public static Object checkcast(Object hub, Object object, Object[] hintHubs, boolean hintsAreExact) {
+        if (object == null) {
+            return object;
+        }
+        Object objectHub = UnsafeLoadNode.load(object, 0, hubOffset(), CiKind.Object);
+        // if we get an exact match: succeed immediately
+        for (int i = 0; i < hintHubs.length; i++) {
+            Object hintHub = hintHubs[i];
+            if (hintHub == objectHub) {
+                return object;
+            }
+        }
+        if (hintsAreExact || TypeCheckSlowPath.check(objectHub, hub) == null) {
+            DeoptimizeNode.deopt(RiDeoptAction.InvalidateReprofile, RiDeoptReason.ClassCastException);
+        }
+        return object;
+    }
+
+    @Fold
+    private static int hubOffset() {
+        return CompilerImpl.getInstance().getConfig().hubOffset;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,86 @@
+/*
+ * 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.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.*;
+
+/**
+ * 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();
+            RiResolvedType[] hints = node.hints();
+            StructuredGraph snippetGraph = (StructuredGraph) checkcast.compilerStorage().get(Graph.class);
+            assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed";
+            HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.length];
+            for (int i = 0; i < hintHubs.length; i++) {
+                hintHubs[i] = ((HotSpotType) hints[i]).klassOop();
+            }
+            assert !node.hintsExact() || hints.length > 0 : "cannot have 0 exact hints!";
+            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), node.hintsExact());
+
+            InliningUtil.inlineSnippet(runtime, node, (FixedWithNextNode) node.anchor(), snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(node.hintsExact()));
+        }
+        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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/AMD64TypeCheckSlowPathOp.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,69 @@
+/*
+ * 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
+ * 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.target.amd64;
+
+import static com.oracle.max.cri.ci.CiValueUtil.*;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.hotspot.*;
+import com.oracle.graal.lir.amd64.*;
+import com.oracle.graal.lir.asm.*;
+import com.oracle.max.asm.target.amd64.*;
+import com.oracle.max.cri.ci.*;
+
+/**
+ * Performs a call to the {@code slow_subtype_check_id} stub.
+ */
+public class AMD64TypeCheckSlowPathOp extends AMD64LIRInstruction {
+
+    public AMD64TypeCheckSlowPathOp(CiValue objectHub, CiValue hub) {
+        super("TYPECHECK_SLOW", new CiValue[] {objectHub}, null, new CiValue[] {objectHub, hub}, NO_OPERANDS, NO_OPERANDS);
+    }
+
+    @Override
+    public void emitCode(TargetMethodAssembler tasm, AMD64MacroAssembler masm) {
+        CiValue result = output(0);
+        CiValue objectHub = input(0);
+        CiValue hub = input(1);
+
+        masm.push(asRegister(objectHub));
+        masm.push(asRegister(hub));
+        AMD64Call.directCall(tasm, masm, CompilerImpl.getInstance().getConfig().instanceofStub, null);
+
+        // Two pops to balance the two pushes above - the value first popped is discarded
+        masm.pop(asRegister(result));
+        masm.pop(asRegister(result));
+    }
+
+    @Override
+    protected EnumSet<OperandFlag> flagsFor(OperandMode mode, int index) {
+        if (mode == OperandMode.Input) {
+            return EnumSet.of(OperandFlag.Register);
+        } else if (mode == OperandMode.Output) {
+            return EnumSet.of(OperandFlag.Register);
+        }
+        throw GraalInternalError.shouldNotReachHere();
+    }
+}
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 09 12:11:36 2012 +0200
@@ -165,7 +165,7 @@
         frameState.clearNonLiveLocals(blockMap.startBlock.localsLiveIn);
 
         // finish the start block
-        ((AbstractStateSplit) lastInstr).setStateAfter(frameState.create(0));
+        lastInstr.setStateAfter(frameState.create(0));
         if (blockMap.startBlock.isLoopHeader) {
             appendGoto(createTarget(blockMap.startBlock, frameState));
         } else {
@@ -255,7 +255,7 @@
         FrameStateBuilder dispatchState = frameState.copy();
         dispatchState.clearStack();
 
-        BeginNode dispatchBegin = currentGraph.add(new BeginNode());
+        BeginNode dispatchBegin = currentGraph.add(new BeginStateSplitNode());
         dispatchBegin.setStateAfter(dispatchState.create(bci));
 
         if (exceptionObject == null) {
@@ -639,7 +639,8 @@
             append(anchor);
             CheckCastNode checkCast;
             RiResolvedType[] hints = getTypeCheckHints((RiResolvedType) type, GraalOptions.CheckcastMaxHints);
-            checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, hints, Util.isFinalClass((RiResolvedType) type)));
+            boolean hintsExact = Util.isFinalClass((RiResolvedType) type);
+            checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, hints, hintsExact));
             append(currentGraph.add(new ValueAnchorNode(checkCast)));
             frameState.apush(checkCast);
         } else {
@@ -1501,7 +1502,7 @@
             }
             if (lastInstr instanceof StateSplit) {
                 StateSplit stateSplit = (StateSplit) lastInstr;
-                if (stateSplit.stateAfter() == null && stateSplit.needsStateAfter()) {
+                if (stateSplit.stateAfter() == null) {
                     stateSplit.setStateAfter(frameState.create(bci));
                 }
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/AbstractStateSplit.java	Wed May 09 12:10:35 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.type.*;
-
-/**
- * The {@code AbstractStateSplit} class is the abstract base class of all instructions
- * that store an immutable copy of the frame state.
- */
-public abstract class AbstractStateSplit extends FixedWithNextNode implements StateSplit {
-
-    @Input(notDataflow = true) private FrameState stateAfter;
-
-    @Override
-    public FrameState stateAfter() {
-        return stateAfter;
-    }
-
-    @Override
-    public void setStateAfter(FrameState x) {
-        assert x == null || x.isAlive() : "frame state must be in a graph";
-        updateUsages(stateAfter, x);
-        stateAfter = x;
-    }
-
-    /**
-     * Creates a new state split with the specified value type.
-     * @param kind the type of the value that this instruction produces
-     */
-    public AbstractStateSplit(Stamp stamp) {
-        super(stamp);
-    }
-
-    @Override
-    public boolean needsStateAfter() {
-        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;
-    }
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public class BeginNode extends AbstractStateSplit implements LIRLowerable, Simplifiable, Node.IterableNodeType {
+public class BeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, Node.IterableNodeType {
     public BeginNode() {
         super(StampFactory.illegal());
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+/**
+ * Base class for {@link BeginNode}s that are associated with a frame state.
+ */
+public class BeginStateSplitNode extends BeginNode implements StateSplit {
+
+    /**
+     * A begin node has no side effect.
+     */
+    @Override
+    public boolean hasSideEffect() {
+        return false;
+    }
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedWithNextNode.java	Wed May 09 12:11:36 2012 +0200
@@ -22,13 +22,43 @@
  */
 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/FrameState.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FrameState.java	Wed May 09 12:11:36 2012 +0200
@@ -282,7 +282,7 @@
 
     @Override
     public void generate(LIRGeneratorTool gen) {
-        // Nothing to do, frame states are processed as part of the handling of AbstractStateSplit nodes.
+        // Nothing to do, frame states are processed as part of the handling of StateSplit nodes.
     }
 
     private static String toString(FrameState frameState) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java	Wed May 09 12:11:36 2012 +0200
@@ -34,7 +34,7 @@
 /**
  * The {@code InvokeNode} represents all kinds of method calls.
  */
-public final class InvokeNode extends AbstractStateSplit implements Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint  {
+public final class InvokeNode extends FixedWithNextNode implements StateSplit, Node.IterableNodeType, Invoke, LIRLowerable, MemoryCheckpoint  {
 
     @Input private final MethodCallTargetNode callTarget;
     private final int bci;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeWithExceptionNode.java	Wed May 09 12:11:36 2012 +0200
@@ -145,6 +145,10 @@
         this.stateAfter = stateAfter;
     }
 
+    public boolean hasSideEffect() {
+        return true;
+    }
+
     public FrameState stateDuring() {
         FrameState tempStateAfter = stateAfter();
         FrameState stateDuring = tempStateAfter.duplicateModified(bci(), tempStateAfter.rethrowException(), this.callTarget.targetMethod().signature().returnKind(false));
@@ -169,11 +173,6 @@
     }
 
     @Override
-    public boolean needsStateAfter() {
-        return true;
-    }
-
-    @Override
     public void intrinsify(Node node) {
         MethodCallTargetNode call = callTarget;
         FrameState state = stateAfter();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/LoopExitNode.java	Wed May 09 12:11:36 2012 +0200
@@ -24,7 +24,7 @@
 
 import com.oracle.graal.nodes.spi.*;
 
-public class LoopExitNode extends BeginNode {
+public class LoopExitNode extends BeginStateSplitNode {
     @Input(notDataflow = true) private LoopBeginNode loopBegin;
     public LoopExitNode(LoopBeginNode loop) {
         assert loop != null;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed May 09 12:11:36 2012 +0200
@@ -32,16 +32,11 @@
 /**
  * Denotes the merging of multiple control-flow paths.
  */
-public class MergeNode extends BeginNode implements Node.IterableNodeType, LIRLowerable {
+public class MergeNode extends BeginStateSplitNode implements Node.IterableNodeType, LIRLowerable {
 
     @Input(notDataflow = true) private final NodeInputList<EndNode> ends = new NodeInputList<>(this);
 
     @Override
-    public boolean needsStateAfter() {
-        return false;
-    }
-
-    @Override
     public void generate(LIRGeneratorTool gen) {
         gen.visitMerge(this);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StateSplit.java	Wed May 09 12:11:36 2012 +0200
@@ -22,6 +22,9 @@
  */
 package com.oracle.graal.nodes;
 
+/**
+ * A state split is a node that may have a frame state associated with it.
+ */
 public interface StateSplit {
 
     /**
@@ -35,9 +38,9 @@
     void setStateAfter(FrameState x);
 
     /**
-     * Determines if the caller should create an {@link #stateAfter() after}
-     * frame state for this node if it doesn't already have one.
+     * Determines if this node has a side-effect. Execution of such a node changes
+     * state visible to other threads. These nodes denote boundaries across which deoptimization
+     * points cannot be moved.
      */
-    boolean needsStateAfter();
-
+    boolean hasSideEffect();
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed May 09 12:11:36 2012 +0200
@@ -64,7 +64,7 @@
 
     private StructuredGraph(String name, RiResolvedMethod method, long graphId) {
         super(name);
-        this.start = add(new BeginNode());
+        this.start = add(new BeginStateSplitNode());
         this.method = method;
         this.graphId = graphId;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AbstractCallNode.java	Wed May 09 12:11:36 2012 +0200
@@ -26,7 +26,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class AbstractCallNode extends AbstractStateSplit implements MemoryCheckpoint {
+public abstract class AbstractCallNode extends FixedWithNextNode implements StateSplit, MemoryCheckpoint {
 
     @Input
     protected final NodeInputList<ValueNode> arguments;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/AccessNode.java	Wed May 09 12:11:36 2012 +0200
@@ -25,7 +25,7 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
-public abstract class AccessNode extends AbstractStateSplit implements Access {
+public abstract class AccessNode extends FixedWithNextNode implements Access {
 
     @Input private ValueNode object;
     @Input private GuardNode guard;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 import com.oracle.graal.nodes.type.*;
 
 
-public final class BoxNode extends AbstractStateSplit implements Node.IterableNodeType {
+public final class BoxNode extends FixedWithNextNode 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	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/MembarNode.java	Wed May 09 12:11:36 2012 +0200
@@ -30,7 +30,7 @@
 /**
  * Creates a memory barrier.
  */
-public class MembarNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint {
+public class MembarNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     private final int barriers;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeAccessNode.java	Wed May 09 12:11:36 2012 +0200
@@ -25,8 +25,11 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.type.*;
 
-
-public abstract class SafeAccessNode extends AbstractStateSplit {
+/**
+ * An analog to {@link AccessNode} with the additional semantics of null-checking
+ * the receiver object before the access.
+ */
+public abstract class SafeAccessNode extends FixedWithNextNode {
 
     @Input private ValueNode object;
     @Input private LocationNode location;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/SafeWriteNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 import com.oracle.max.cri.ri.*;
 
 
-public class SafeWriteNode extends SafeAccessNode implements Lowerable{
+public class SafeWriteNode extends SafeAccessNode implements StateSplit, Lowerable{
 
     @Input private ValueNode value;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeLoadNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 /**
  * Load of a value from a location specified as an offset relative to an object.
  */
-public class UnsafeLoadNode extends AbstractStateSplit implements Lowerable {
+public class UnsafeLoadNode extends FixedWithNextNode implements Lowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeStoreNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 /**
  * Store of a value at a location specified as an offset relative to an object.
  */
-public class UnsafeStoreNode extends AbstractStateSplit implements Lowerable {
+public class UnsafeStoreNode extends FixedWithNextNode implements StateSplit, Lowerable {
 
     @Input private ValueNode object;
     @Input private ValueNode offset;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteMemoryCheckpointNode.java	Wed May 09 12:11:36 2012 +0200
@@ -27,7 +27,7 @@
 import com.oracle.graal.nodes.type.*;
 
 
-public final class WriteMemoryCheckpointNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint {
+public final class WriteMemoryCheckpointNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     public WriteMemoryCheckpointNode() {
         this(StampFactory.illegal());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/WriteNode.java	Wed May 09 12:11:36 2012 +0200
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.type.*;
 
 
-public final class WriteNode extends AccessNode implements LIRLowerable {
+public final class WriteNode extends AccessNode implements StateSplit, LIRLowerable {
     @Input private ValueNode value;
 
     public ValueNode value() {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessArrayNode.java	Wed May 09 12:11:36 2012 +0200
@@ -28,7 +28,7 @@
 /**
  * This the base class of all array operations.
  */
-public abstract class AccessArrayNode extends AbstractStateSplit {
+public abstract class AccessArrayNode extends FixedWithNextNode {
 
     @Input private ValueNode array;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessFieldNode.java	Wed May 09 12:11:36 2012 +0200
@@ -35,7 +35,7 @@
 /**
  * The base class of all instructions that access fields.
  */
-public abstract class AccessFieldNode extends AbstractStateSplit implements Lowerable {
+public abstract class AccessFieldNode extends FixedWithNextNode implements Lowerable {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/AccessMonitorNode.java	Wed May 09 12:11:36 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 AbstractStateSplit implements MemoryCheckpoint {
+public abstract class AccessMonitorNode extends FixedWithNextNode implements StateSplit, MemoryCheckpoint {
 
     @Input private ValueNode object;
     private boolean eliminated;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CompareAndSwapNode.java	Wed May 09 12:11:36 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 AbstractStateSplit implements LIRLowerable, Lowerable, MemoryCheckpoint {
+public class CompareAndSwapNode extends FixedWithNextNode 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	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ExceptionObjectNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 /**
  * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler.
  */
-public class ExceptionObjectNode extends AbstractStateSplit implements LIRLowerable, MemoryCheckpoint {
+public class ExceptionObjectNode extends FixedWithNextNode implements StateSplit, LIRLowerable, MemoryCheckpoint {
 
     /**
      * Constructs a new ExceptionObject instruction.
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadFieldNode.java	Wed May 09 12:11:36 2012 +0200
@@ -55,11 +55,6 @@
     }
 
     @Override
-    public boolean needsStateAfter() {
-        return false;
-    }
-
-    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         CiConstant constant = null;
         if (isStatic()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/LoadIndexedNode.java	Wed May 09 12:11:36 2012 +0200
@@ -58,11 +58,6 @@
     }
 
     @Override
-    public boolean needsStateAfter() {
-        return false;
-    }
-
-    @Override
     public void lower(CiLoweringTool tool) {
         tool.getRuntime().lower(this, tool);
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/RegisterFinalizerNode.java	Wed May 09 12:11:36 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 AbstractStateSplit implements Canonicalizable, LIRLowerable {
+public final class RegisterFinalizerNode extends FixedWithNextNode implements StateSplit, Canonicalizable, LIRLowerable {
 
     @Input private ValueNode object;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreFieldNode.java	Wed May 09 12:11:36 2012 +0200
@@ -29,7 +29,7 @@
 /**
  * The {@code StoreFieldNode} represents a write to a static or instance field.
  */
-public final class StoreFieldNode extends AccessFieldNode {
+public final class StoreFieldNode extends AccessFieldNode implements StateSplit {
 
     @Input private ValueNode value;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/StoreIndexedNode.java	Wed May 09 12:11:36 2012 +0200
@@ -31,7 +31,7 @@
 /**
  * The {@code StoreIndexedNode} represents a write to an array element.
  */
-public final class StoreIndexedNode extends AccessIndexedNode implements Lowerable {
+public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable {
 
     @Input private ValueNode value;
 
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinterDumpHandler.java	Wed May 09 12:11:36 2012 +0200
@@ -160,7 +160,7 @@
     }
 
     private void openScope(String name) {
-        printer.beginGroup(name, name, Debug.contextLookup(RiResolvedMethod.class), -1);
+        printer.beginGroup(Thread.currentThread().getName() + ":" + name, name, Debug.contextLookup(RiResolvedMethod.class), -1);
     }
 
     private void closeScope() {
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippet.java	Wed May 09 12:11:36 2012 +0200
@@ -24,8 +24,17 @@
 
 import java.lang.annotation.*;
 
+import com.oracle.graal.graph.Node.NodeIntrinsic;
+
+/**
+ * A snippet is a Graal graph expressed as a Java source method. Graal snippets can be used for:
+ * <ul>
+ * <li>intrinsifying native JDK methods (see {@link ClassSubstitution})</li>
+ * <li>lowering operations that have runtime dependent semantics (e.g. the {@code CHECKCAST} bytecode) </li>
+ * <li>replacing a method call with a single graph node (see {@link NodeIntrinsic})</li>
+ * </ul>
+ */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
 public @interface Snippet {
-
 }
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/Snippets.java	Wed May 09 12:11:36 2012 +0200
@@ -53,16 +53,18 @@
         }
     }
 
-    private static void installSnippets(GraalRuntime runtime, CiTarget target, Class< ? extends SnippetsInterface> clazz,
-                    BoxingMethodPool pool) {
-        for (Method snippet : clazz.getDeclaredMethods()) {
-            int modifiers = snippet.getModifiers();
-            if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
-                throw new RuntimeException("Snippet must not be abstract or native");
-            }
-            RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet);
-            if (snippetRiMethod.compilerStorage().get(Graph.class) == null) {
-                buildSnippetGraph(snippetRiMethod, runtime, target, pool);
+    private static void installSnippets(GraalRuntime runtime, CiTarget target, Class< ? extends SnippetsInterface> clazz, BoxingMethodPool pool) {
+        for (Method method : clazz.getDeclaredMethods()) {
+            if (method.getAnnotation(Snippet.class) != null) {
+                Method snippet = method;
+                int modifiers = snippet.getModifiers();
+                if (Modifier.isAbstract(modifiers) || Modifier.isNative(modifiers)) {
+                    throw new RuntimeException("Snippet must not be abstract or native");
+                }
+                RiResolvedMethod snippetRiMethod = runtime.getRiMethod(snippet);
+                if (snippetRiMethod.compilerStorage().get(Graph.class) == null) {
+                    buildSnippetGraph(snippetRiMethod, runtime, target, pool);
+                }
             }
         }
     }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/CompiledMethodTest.java	Wed May 09 12:11:36 2012 +0200
@@ -69,7 +69,7 @@
 
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
         CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod);
+        RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
         try {
             Object result = compiledMethod.execute("1", "2", "3");
             Assert.assertEquals("1-2-3", result);
@@ -84,7 +84,7 @@
         final StructuredGraph graph = parse(method);
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
         CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod);
+        RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
         try {
             Object result = compiledMethod.executeVarargs("1", "2", "3");
             Assert.assertEquals("1 2 3", result);
@@ -99,7 +99,7 @@
         final StructuredGraph graph = parse(method);
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
         CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod);
+        RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
         try {
             f1 = "0";
             Object result = compiledMethod.executeVarargs(this, "1", "2", "3");
@@ -128,7 +128,7 @@
         }
 
         CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
-        final RiCompiledMethod compiledMethod = runtime.addMethod(riMethod, targetMethod);
+        final RiCompiledMethod compiledMethod = addMethod(riMethod, targetMethod);
 
         final CompilableObject compilableObject = new CompilableObjectImpl(0);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalAccess.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,86 @@
+/*
+ * 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 java.util.*;
+
+import com.oracle.graal.compiler.*;
+
+/**
+ * Utility for getting a Graal objects from the current execution environment.
+ */
+class GraalAccess {
+
+    /**
+     * The known classes declaring a {@code getGraalCompiler()} method. These class names
+     * have aliases that can be used with the {@code "graal.access"} system property to
+     * specify the VM environment to try first when getting a Graal compiler instance.
+     */
+    private static Map<String, String> graalAccessClasses = new LinkedHashMap<>();
+    static {
+        graalAccessClasses.put("HotSpot", "com.oracle.graal.hotspot.CompilerImpl");
+        graalAccessClasses.put("Maxine", "com.oracle.max.vm.ext.maxri.MaxRuntime");
+    }
+
+    /**
+     * Gets a {@link GraalCompiler} instance from the current execution environment.
+     */
+    static GraalCompiler getGraalCompiler() {
+        String vm = System.getProperty("graal.access");
+        if (vm != null) {
+            String cn = graalAccessClasses.get(vm);
+            if (cn != null) {
+                GraalCompiler graalCompiler = getGraalCompiler(cn);
+                if (graalCompiler != null) {
+                    return graalCompiler;
+                }
+            }
+        }
+
+        for (String className : graalAccessClasses.values()) {
+            GraalCompiler graalCompiler = getGraalCompiler(className);
+            if (graalCompiler != null) {
+                return graalCompiler;
+            }
+        }
+        throw new InternalError("Could not create a GraalRuntime instance");
+    }
+
+    /**
+     * Calls {@code getGraalCompiler()} via reflection on a given class.
+     *
+     * @return {@code null} if there was an error invoking the method or if the method returns {@code null} itself
+     */
+    private static GraalCompiler getGraalCompiler(String className) {
+        try {
+            Class<?> c = Class.forName(className);
+            Method m = c.getDeclaredMethod("getGraalCompiler");
+            return (GraalCompiler) m.invoke(null);
+        } catch (Exception e) {
+            //e.printStackTrace();
+            System.err.println(e);
+            return null;
+        }
+    }
+}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraalRuntimeAccess.java	Wed May 09 12:10:35 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +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 java.util.*;
-
-import com.oracle.graal.cri.*;
-
-/**
- * Utility for getting a {@link GraalRuntime} instance from the current execution environment.
- */
-class GraalRuntimeAccess {
-
-    /**
-     * The known classes declaring a {@code getGraalRuntime()} method. These class names
-     * have aliases that can be used with the {@code "graal.runtime"} system property to
-     * specify the VM environment to try first when getting a Graal runtime instance.
-     */
-    private static Map<String, String> graalRuntimeFactoryClasses = new LinkedHashMap<>();
-    static {
-        graalRuntimeFactoryClasses.put("HotSpot", "com.oracle.graal.hotspot.CompilerImpl");
-        graalRuntimeFactoryClasses.put("Maxine", "com.oracle.max.vm.ext.maxri.MaxRuntime");
-    }
-
-    /**
-     * Gets a Graal runtime instance from the current execution environment.
-     */
-    static GraalRuntime getGraalRuntime() {
-        String vm = System.getProperty("graal.runtime");
-        if (vm != null) {
-            String cn = graalRuntimeFactoryClasses.get(vm);
-            if (cn != null) {
-                GraalRuntime graal = getGraalRuntime(cn);
-                if (graal != null) {
-                    return graal;
-                }
-            }
-        }
-
-        for (String className : graalRuntimeFactoryClasses.values()) {
-            GraalRuntime graal = getGraalRuntime(className);
-            if (graal != null) {
-                return graal;
-            }
-        }
-        throw new InternalError("Could not create a GraalRuntime instance");
-    }
-
-    /**
-     * Calls {@code getGraalRuntime()} via reflection on a given class.
-     *
-     * @return {@code null} if there was an error invoking the methodor if the method return {@code null} itself
-     */
-    private static GraalRuntime getGraalRuntime(String className) {
-        try {
-            Class<?> c = Class.forName(className);
-            Method m = c.getDeclaredMethod("getGraalRuntime");
-            return (GraalRuntime) m.invoke(null);
-        } catch (Exception e) {
-            //e.printStackTrace();
-            System.err.println(e);
-            return null;
-        }
-    }
-}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Wed May 09 12:11:36 2012 +0200
@@ -23,6 +23,7 @@
 package com.oracle.graal.compiler.tests;
 
 import java.lang.reflect.*;
+import java.util.concurrent.*;
 
 import junit.framework.*;
 
@@ -33,6 +34,7 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.java.*;
 import com.oracle.graal.nodes.*;
+import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 
 /**
@@ -40,7 +42,7 @@
  * for Graal compiler transformations. The general pattern for a test is:
  * <ol>
  * <li>Create a graph by {@linkplain #parse(String) parsing} a method.</li>
- * <li>Manually modify the graph (e.g. replace a paramter node with a constant).</li>
+ * <li>Manually modify the graph (e.g. replace a parameter node with a constant).</li>
  * <li>Apply a transformation to the graph.</li>
  * <li>Assert that the transformed graph is equal to an expected graph.</li>
  * </ol>
@@ -53,11 +55,13 @@
  */
 public abstract class GraphTest {
 
+    protected final GraalCompiler graalCompiler;
     protected final GraalRuntime runtime;
 
     public GraphTest() {
         Debug.enable();
-        this.runtime = GraalRuntimeAccess.getGraalRuntime();
+        this.graalCompiler = GraalAccess.getGraalCompiler();
+        this.runtime = graalCompiler.runtime;
     }
 
     protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
@@ -96,6 +100,21 @@
         }
     }
 
+    protected RiCompiledMethod addMethod(final RiResolvedMethod method, final CiTargetMethod tm) {
+        Debug.scope("CodeInstall", new Object[] {graalCompiler, method}, new Callable<RiCompiledMethod>() {
+            @Override
+            public RiCompiledMethod call() throws Exception {
+                final RiCodeInfo[] info = Debug.isDumpEnabled() ? new RiCodeInfo[1] : null;
+                RiCompiledMethod installedMethod = runtime.addMethod(method, tm, info);
+                if (info != null) {
+                    Debug.dump(info[0], "After code installation");
+                }
+                return installedMethod;
+            }
+        });
+        return runtime.addMethod(method, tm, null);
+    }
+
     /**
      * Parses a Java method to produce a graph.
      *
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Wed May 09 12:11:36 2012 +0200
@@ -0,0 +1,135 @@
+/*
+ * 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.*;
+
+public class LowerCheckCastTest extends GraphTest {
+
+    static {
+        // Ensure that the methods to be compiled and executed are fully resolved
+        asNumber(0);
+        asString("0");
+        asNumberExt(0);
+        asStringExt("0");
+    }
+
+    private RiCompiledMethod compile(String name, Class[] hintClasses, boolean exact) {
+        //System.out.println("compiling: " + name + ", hints=" + Arrays.toString(hintClasses) + ", exact=" + exact);
+
+        Method method = getMethod(name);
+        final StructuredGraph graph = parse(method);
+
+        RiResolvedType[] hints = new RiResolvedType[hintClasses.length];
+        for (int i = 0; i < hintClasses.length; i++) {
+            hints[i] = runtime.getType(hintClasses[i]);
+        }
+
+        CheckCastNode ccn = graph.getNodes(CheckCastNode.class).first();
+        assert ccn != null;
+        CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.anchor(), ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), hints, exact));
+        graph.replaceFloating(ccn, ccnNew);
+
+        final RiResolvedMethod riMethod = runtime.getRiMethod(method);
+        CiTargetMethod targetMethod = runtime.compile(riMethod, graph);
+        return addMethod(riMethod, targetMethod);
+    }
+
+    private static final boolean EXACT = true;
+    private static final boolean NOT_EXACT = false;
+
+    private static Class[] hints(Class... classes) {
+        return classes;
+    }
+
+    private void test(String name, Class[] hints, boolean exact, Object expected, Object... args) {
+        RiCompiledMethod compiledMethod = compile(name, hints, exact);
+        Assert.assertEquals(expected, compiledMethod.executeVarargs(args));
+    }
+
+    @Test
+    public void test1() {
+        test("asNumber",    hints(),                        NOT_EXACT, 111, 111);
+        test("asNumber",    hints(Integer.class),           NOT_EXACT, 111, 111);
+        test("asNumber",    hints(Long.class, Short.class), NOT_EXACT, 111, 111);
+        test("asNumberExt", hints(),                        NOT_EXACT, 121, 111);
+        test("asNumberExt", hints(Integer.class),           NOT_EXACT, 121, 111);
+        test("asNumberExt", hints(Long.class, Short.class), NOT_EXACT, 121, 111);
+    }
+
+    @Test
+    public void test2() {
+        test("asString",    hints(),             NOT_EXACT, "111", "111");
+        test("asString",    hints(String.class), EXACT,     "111", "111");
+        test("asString",    hints(String.class), NOT_EXACT, "111", "111");
+
+        test("asStringExt", hints(),             NOT_EXACT, "#111", "111");
+        test("asStringExt", hints(String.class), EXACT,     "#111", "111");
+        test("asStringExt", hints(String.class), NOT_EXACT, "#111", "111");
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void test3() {
+        test("asNumber", hints(), NOT_EXACT, 111, "111");
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void test4() {
+        test("asString", hints(String.class), EXACT, "111", 111);
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void test5() {
+        test("asNumberExt", hints(), NOT_EXACT, 111, "111");
+    }
+
+    @Test(expected = ClassCastException.class)
+    public void test6() {
+        test("asStringExt", hints(String.class), EXACT, "111", 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;
+    }
+}
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ci/CiKind.java	Wed May 09 12:11:36 2012 +0200
@@ -23,6 +23,9 @@
 package com.oracle.max.cri.ci;
 
 import static com.oracle.max.cri.ci.CiKind.Flags.*;
+
+import java.lang.reflect.*;
+
 import sun.misc.*;
 
 import com.oracle.max.cri.ri.*;
@@ -297,6 +300,8 @@
                     return String.valueOf(value);
                 } else if (value instanceof Class< ? >) {
                     return ((Class< ? >) value).getName() + ".class";
+                } else if (value.getClass().isArray()) {
+                    return formatArray(value);
                 } else {
                     return CiUtil.getSimpleName(value.getClass(), true) + "@" + System.identityHashCode(value);
                 }
@@ -306,6 +311,35 @@
         }
     }
 
+    private static final int MAX_FORMAT_ARRAY_LENGTH = Integer.getInteger("maxFormatArrayLength", 5);
+
+    private static String formatArray(Object array) {
+        Class< ? > componentType = array.getClass().getComponentType();
+        assert componentType != null;
+        int arrayLength = Array.getLength(array);
+        StringBuilder buf = new StringBuilder(CiUtil.getSimpleName(componentType, true)).
+                        append('[').
+                        append(arrayLength).
+                        append("]{");
+        int length = Math.min(MAX_FORMAT_ARRAY_LENGTH, arrayLength);
+        boolean primitive = componentType.isPrimitive();
+        for (int i = 0; i < length; i++) {
+            if (primitive) {
+                buf.append(Array.get(array, i));
+            } else {
+                Object o = ((Object[]) array)[i];
+                buf.append(CiKind.Object.format(o));
+            }
+            if (i != length - 1) {
+                buf.append(", ");
+            }
+        }
+        if (arrayLength != length) {
+            buf.append(", ...");
+        }
+        return buf.append('}').toString();
+    }
+
     public final char signatureChar() {
         return Character.toUpperCase(typeChar);
     }
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java	Wed May 09 12:10:35 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiRuntime.java	Wed May 09 12:11:36 2012 +0200
@@ -176,17 +176,20 @@
      *
      * @param method a method whose executable code is being modified
      * @param code the code to be executed when {@code method} is called
-     * @param info the object into which details of the installed code will be written (ignored if null)
+     * @param info the object into which details of the installed code will be written.
+     *        Ignored if null, otherwise the info is written to index 0 of this array.
      */
-    void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo info);
+    void installMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info);
 
     /**
      * Adds the given machine code as an implementation of the given method without making it the default implementation.
      * @param method a method to which the executable code is begin added
      * @param code the code to be added
+     * @param info the object into which details of the installed code will be written.
+     *        Ignored if null, otherwise the info is written to index 0 of this array.
      * @return a reference to the compiled and ready-to-run code
      */
-    RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code);
+    RiCompiledMethod addMethod(RiResolvedMethod method, CiTargetMethod code, RiCodeInfo[] info);
 
     /**
      * Encodes a deoptimization action and a deoptimization reason in an integer value.
--- a/mx/commands.py	Wed May 09 12:10:35 2012 +0200
+++ b/mx/commands.py	Wed May 09 12:11:36 2012 +0200
@@ -51,15 +51,6 @@
 
 _make_eclipse_launch = False
 
-_jacocoExcludes = ['com.oracle.graal.hotspot.snippets.ArrayCopySnippets',
-                   'com.oracle.graal.snippets.DoubleSnippets',
-                   'com.oracle.graal.snippets.FloatSnippets',
-                   'com.oracle.graal.snippets.MathSnippetsX86',
-                   'com.oracle.graal.snippets.NodeClassSnippets',
-                   'com.oracle.graal.hotspot.snippets.SystemSnippets',
-                   'com.oracle.graal.hotspot.snippets.UnsafeSnippets',
-                   'com.oracle.graal.compiler.tests.*']
-
 _copyrightTemplate = """/*
  * Copyright (c) {0}, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -571,16 +562,49 @@
         args = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=' + str(mx.java().debug_port)] + args
     if _jacoco == 'on' or _jacoco == 'append':
         jacocoagent = mx.library("JACOCOAGENT", True)
+        # Exclude all compiler tests and snippets
+        excludes = ['com.oracle.graal.compiler.tests.*']
+        for p in mx.projects():
+            for s in p.source_dirs():
+                _add_classes_with_annotation(excludes, s, None, '@Snippet')
+                _add_classes_with_annotation(excludes, s, None, '@ClassSubstitution')
         agentOptions = {
                         'append' : 'true' if _jacoco == 'append' else 'false',
                         'bootclasspath' : 'true',
                         'includes' : 'com.oracle.*',
-                        'excludes' : ':'.join(_jacocoExcludes)
+                        'excludes' : ':'.join(excludes)
         }
         args = ['-javaagent:' + jacocoagent.get_path(True) + '=' + ','.join([k + '=' + v for k, v in agentOptions.items()])] + args
     exe = join(_jdk(build), 'bin', mx.exe_suffix('java'))
     return mx.run([exe, '-' + vm] + args, nonZeroIsFatal=nonZeroIsFatal, out=out, err=err, cwd=cwd, timeout=timeout)
 
+def _add_classes_with_annotation(classes, srcDir, pkgRoot, annotation):
+    """
+    Scan 'srcDir' for Java source files containing a line starting with 'annotation'
+    (ignoring preceding whitespace) and add the fully qualified class name
+    to 'classes' for each Java source file matched.
+    """
+    pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$")
+    for root, _, files in os.walk(srcDir):
+        for name in files:
+            if name.endswith('.java') and name != 'package-info.java':
+                hasTest = False
+                with open(join(root, name)) as f:
+                    pkg = None
+                    for line in f:
+                        if line.startswith("package "):
+                            match = pkgDecl.match(line)
+                            if match:
+                                pkg = match.group(1)
+                        else:
+                            if line.strip().startswith(annotation):
+                                hasTest = True
+                                break
+                if hasTest:
+                    assert pkg is not None
+                    if pkgRoot is None or pkg.startswith(pkgRoot):
+                        classes.append(pkg + '.' + name[:-len('.java')])
+
 
 # Table of unit tests.
 # Keys are project names, values are package name lists.
@@ -594,28 +618,6 @@
     'com.oracle.graal.jtt': ['com.oracle.graal.jtt'],
 }
 
-def _add_test_classes(testClassList, searchDir, pkgRoot):
-    pkgDecl = re.compile(r"^package\s+([a-zA-Z_][\w\.]*)\s*;$")
-    for root, _, files in os.walk(searchDir):
-        for name in files:
-            if name.endswith('.java') and name != 'package-info.java':
-                hasTest = False
-                with open(join(root, name)) as f:
-                    pkg = None
-                    for line in f:
-                        if line.startswith("package "):
-                            match = pkgDecl.match(line)
-                            if match:
-                                pkg = match.group(1)
-                        else:
-                            if line.strip().startswith('@Test'):
-                                hasTest = True
-                                break
-                if hasTest:
-                    assert pkg is not None
-                    if pkg.startswith(pkgRoot):
-                        testClassList.append(pkg + '.' + name[:-len('.java')])
-
 def unittest(args):
     """run the Graal Compiler Unit Tests in the GraalVM
     
@@ -637,13 +639,13 @@
         p = mx.project(proj)
         classes = []
         for pkg in _unittests[proj]:
-            _add_test_classes(classes, join(p.dir, 'src'), pkg)
+            _add_classes_with_annotation(classes, join(p.dir, 'src'), pkg, '@Test')
     
         if len(pos) != 0:
             classes = [c for c in classes if containsAny(c, pos)]
         if len(neg) != 0:
             classes = [c for c in classes if not containsAny(c, neg)]
-            
+        
         vm(['-XX:-BootstrapGraal', '-esa'] + vmArgs + ['-cp', mx.classpath(proj), 'org.junit.runner.JUnitCore'] + classes)
     
 def jtt(args):
@@ -667,7 +669,7 @@
         p = mx.project(proj)
         classes = []
         for pkg in _jtttests[proj]:
-            _add_test_classes(classes, join(p.dir, 'src'), pkg)
+            _add_classes_with_annotation(classes, join(p.dir, 'src'), pkg, '@Test')
     
         if len(pos) != 0:
             classes = [c for c in classes if containsAny(c, pos)]