changeset 5385:31ec401eb592

Merge
author Lukas Stadler <lukas.stadler@jku.at>
date Thu, 10 May 2012 14:24:25 +0200
parents 4485e0edd1af (diff) c7f92c6246ba (current diff)
children 19e5dc8d0891
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java
diffstat 28 files changed, 404 insertions(+), 268 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Thu May 10 14:24:25 2012 +0200
@@ -90,7 +90,7 @@
                 });
                 final FrameMap frameMap = Debug.scope("BackEnd", lir, new Callable<FrameMap>() {
                     public FrameMap call() {
-                        return emitLIR(lir, graph, method);
+                        return emitLIR(lir, graph, method, assumptions);
                     }
                 });
                 return Debug.scope("CodeGen", frameMap, new Callable<CiTargetMethod>() {
@@ -235,9 +235,9 @@
         });
     }
 
-    public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final RiResolvedMethod method) {
+    public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final RiResolvedMethod method, CiAssumptions assumptions) {
         final FrameMap frameMap = backend.newFrameMap(runtime.getRegisterConfig(method));
-        final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir, xir);
+        final LIRGenerator lirGenerator = backend.newLIRGenerator(graph, frameMap, method, lir, xir, assumptions);
 
         Debug.scope("LIRGen", lirGenerator, new Runnable() {
             public void run() {
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Thu May 10 14:24:25 2012 +0200
@@ -246,6 +246,14 @@
      */
     public static int CheckcastMaxHints = 2;
 
+    /**
+     * @see #CheckcastMinHintHitProbability
+     */
+    public static double InstanceOfMinHintHitProbability = 0.5;
+
+    /**
+     * @see #CheckcastMaxHints
+     */
     public static int InstanceOfMaxHints = 1;
 
     /**
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Thu May 10 14:24:25 2012 +0200
@@ -141,7 +141,7 @@
     private LockScope curLocks;
 
 
-    public LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) {
+    public LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions) {
         this.graph = graph;
         this.runtime = runtime;
         this.target = target;
@@ -150,7 +150,7 @@
         this.nodeOperands = graph.createNodeMap();
         this.lir = lir;
         this.xir = xir;
-        this.xirSupport = new XirSupport();
+        this.xirSupport = new XirSupport(assumptions);
         this.debugInfoBuilder = new DebugInfoBuilder(nodeOperands);
         this.blockLocks = new BlockMap<>(lir.cfg);
         this.blockLastState = new BlockMap<>(lir.cfg);
@@ -509,7 +509,7 @@
 
     @Override
     public void visitCheckCast(CheckCastNode x) {
-        XirSnippet snippet = xir.genCheckCast(site(x, x.object()), toXirArgument(x.object()), toXirArgument(x.targetClassInstruction()), x.targetClass(), x.hints(), x.hintsExact());
+        XirSnippet snippet = xir.genCheckCast(site(x, x.object()), toXirArgument(x.object()), toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile());
         emitXir(snippet, x, state(), true);
         // The result of a checkcast is the unmodified object, so no need to allocate a new variable for it.
         setResult(x, operand(x.object()));
@@ -716,7 +716,7 @@
 
     private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
         XirArgument obj = toXirArgument(x.object());
-        XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.hints(), x.hintsExact());
+        XirSnippet snippet = xir.genInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), x.profile());
         emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor);
     }
 
@@ -767,7 +767,7 @@
         XirArgument obj = toXirArgument(x.object());
         XirArgument trueArg = toXirArgument(x.negated() ? falseValue : trueValue);
         XirArgument falseArg = toXirArgument(x.negated() ? trueValue : falseValue);
-        XirSnippet snippet = xir.genMaterializeInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), x.hints(), x.hintsExact());
+        XirSnippet snippet = xir.genMaterializeInstanceOf(site(x, x.object()), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), x.profile());
         return (Variable) emitXir(snippet, null, null, false);
     }
 
@@ -1358,9 +1358,15 @@
      * Implements site-specific information for the XIR interface.
      */
     static class XirSupport implements XirSite {
+        final CiAssumptions assumptions;
         ValueNode current;
         ValueNode receiver;
 
+
+        public XirSupport(CiAssumptions assumptions) {
+            this.assumptions = assumptions;
+        }
+
         public boolean isNonNull(XirArgument argument) {
             return false;
         }
@@ -1385,6 +1391,10 @@
             return true;
         }
 
+        public CiAssumptions assumptions() {
+            return assumptions;
+        }
+
         XirSupport site(ValueNode v, ValueNode r) {
             current = v;
             receiver = r;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/SnippetIntrinsificationPhase.java	Thu May 10 14:24:25 2012 +0200
@@ -255,7 +255,10 @@
                         assert false : "unexpected checkcast usage: " + checkCastUsage;
                     }
                 }
-                checkCastNode.safeDelete();
+                FixedNode next = checkCastNode.next();
+                checkCastNode.setNext(null);
+                checkCastNode.replaceAtPredecessors(next);
+                GraphUtil.killCFG(checkCastNode);
             }
         }
     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Thu May 10 14:24:25 2012 +0200
@@ -72,7 +72,7 @@
         return new FrameMap(runtime, target, registerConfig);
     }
 
-    public abstract LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir);
+    public abstract LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions);
 
     public abstract TargetMethodAssembler newAssembler(FrameMap frameMap, LIR lir);
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Thu May 10 14:24:25 2012 +0200
@@ -96,8 +96,8 @@
         }
     }
 
-    public AMD64LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) {
-        super(graph, runtime, target, frameMap, method, lir, xir);
+    public AMD64LIRGenerator(Graph graph, RiRuntime runtime, CiTarget target, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions) {
+        super(graph, runtime, target, frameMap, method, lir, xir, assumptions);
         lir.spillMoveFactory = new AMD64SpillMoveFactory();
     }
 
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Thu May 10 14:24:25 2012 +0200
@@ -228,7 +228,12 @@
                                 }
                             }
                             ValueNode replacement = canonical.replacement;
-                            currentGraph.replaceFloating((FloatingNode) node, replacement);
+                            if (node instanceof FloatingNode) {
+                                currentGraph.replaceFloating((FloatingNode) node, replacement);
+                            } else {
+                                assert node instanceof FixedWithNextNode;
+                                currentGraph.replaceFixed((FixedWithNextNode) node, replacement);
+                            }
                             changedNodes.addAll(replacement.usages());
                         }
                     }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java	Thu May 10 14:24:25 2012 +0200
@@ -22,15 +22,13 @@
  */
 package com.oracle.graal.compiler.util;
 
-import java.lang.reflect.*;
 import java.util.*;
 
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.criutils.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.criutils.*;
 
 /**
  * The {@code Util} class contains a motley collection of utility methods used throughout the compiler.
@@ -357,8 +355,4 @@
     public static boolean isFloating(Node n) {
         return n instanceof FloatingNode;
     }
-
-    public static boolean isFinalClass(RiResolvedType type) {
-        return Modifier.isFinal(type.accessFlags()) || (type.isArrayClass() && Modifier.isFinal(type.componentType().accessFlags()));
-    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/VMToCompilerImpl.java	Thu May 10 14:24:25 2012 +0200
@@ -160,8 +160,6 @@
         }
     }
 
-
-
     /**
      * 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
@@ -237,18 +235,27 @@
         compileMethod((HotSpotMethodResolved) riMethod, 0, false, 10);
     }
 
+    private static void shutdownCompileQueue(ThreadPoolExecutor queue) throws InterruptedException {
+        if (queue != null) {
+            queue.shutdown();
+            if (Debug.isEnabled() && GraalOptions.Dump != null) {
+                // Wait 5 seconds to try and flush out all graph dumps
+                queue.awaitTermination(5, TimeUnit.SECONDS);
+            }
+        }
+    }
+
     public void shutdownCompiler() throws Throwable {
         try {
             assert !CompilationTask.withinEnqueue.get();
             CompilationTask.withinEnqueue.set(Boolean.TRUE);
-            compileQueue.shutdown();
-            if (slowCompileQueue != null) {
-                slowCompileQueue.shutdown();
-            }
+            shutdownCompileQueue(compileQueue);
+            shutdownCompileQueue(slowCompileQueue);
         } finally {
             CompilationTask.withinEnqueue.set(Boolean.FALSE);
         }
 
+
         if (Debug.isEnabled()) {
             List<DebugValueMap> topLevelMaps = DebugValueMap.getTopLevelMaps();
             List<DebugValue> debugValues = KeyRegistry.getDebugValues();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java	Thu May 10 14:24:25 2012 +0200
@@ -386,7 +386,7 @@
             Arrays.sort(ptypes);
 
             double notRecordedTypeProbability = entries < config.typeProfileWidth ? 0.0 : Math.min(1.0, Math.max(0.0, 1.0 - totalProbability));
-            return new RiTypeProfile(ptypes, notRecordedTypeProbability);
+            return new RiTypeProfile(notRecordedTypeProbability, ptypes);
         }
 
         private static int getReceiverOffset(int row) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotRuntime.java	Thu May 10 14:24:25 2012 +0200
@@ -336,21 +336,21 @@
                 if (array.exactType() != null) {
                     RiResolvedType elementType = array.exactType().componentType();
                     if (elementType.superType() != null) {
-                        AnchorNode anchor = graph.add(new AnchorNode());
-                        graph.addBeforeFixed(storeIndexed, anchor);
                         ConstantNode type = ConstantNode.forCiConstant(elementType.getEncoding(Representation.ObjectHub), this, graph);
-                        value = graph.unique(new CheckCastNode(anchor, type, elementType, value));
+                        CheckCastNode checkcast = graph.add(new CheckCastNode(type, elementType, value));
+                        graph.addBeforeFixed(storeIndexed, checkcast);
+                        value = checkcast;
                     } else {
                         assert elementType.name().equals("Ljava/lang/Object;") : elementType.name();
                     }
                 } else {
-                    AnchorNode anchor = graph.add(new AnchorNode());
-                    graph.addBeforeFixed(storeIndexed, anchor);
                     GuardNode guard = (GuardNode) tool.createGuard(graph.unique(new NullCheckNode(array, false)), RiDeoptReason.NullCheckException, RiDeoptAction.InvalidateReprofile, StructuredGraph.INVALID_GRAPH_ID);
                     FloatingReadNode arrayClass = graph.unique(new FloatingReadNode(array, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph), StampFactory.objectNonNull()));
                     arrayClass.setGuard(guard);
                     FloatingReadNode arrayElementKlass = graph.unique(new FloatingReadNode(arrayClass, null, LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.arrayClassElementOffset, graph), StampFactory.objectNonNull()));
-                    value = graph.unique(new CheckCastNode(anchor, arrayElementKlass, null, value));
+                    CheckCastNode checkcast = graph.add(new CheckCastNode(arrayElementKlass, null, value));
+                    graph.addBeforeFixed(storeIndexed, checkcast);
+                    value = checkcast;
                 }
             }
             WriteNode memoryWrite = graph.add(new WriteNode(array, value, arrayLocation));
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Thu May 10 14:24:25 2012 +0200
@@ -45,6 +45,7 @@
 import com.oracle.max.cri.xir.CiXirAssembler.XirMark;
 import com.oracle.max.cri.xir.CiXirAssembler.XirOperand;
 import com.oracle.max.cri.xir.CiXirAssembler.XirParameter;
+import com.oracle.max.criutils.*;
 
 public class HotSpotXirGenerator implements RiXirGenerator {
 
@@ -806,9 +807,11 @@
     }
 
     @Override
-    public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiResolvedType[] hints, boolean hintsExact) {
+    public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiTypeProfile profile) {
         final boolean useCounters = GraalOptions.CheckcastCounters;
-        if (hints == null || hints.length == 0) {
+        TypeCheckHints hints = new TypeCheckHints(type, profile, site.assumptions(), GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
+        int hintsLength = hints.types.length;
+        if (hintsLength == 0) {
             if (useCounters) {
                 if (type == null) {
                     return new XirSnippet(checkCastTemplates.get(site, 0, NULL_TYPE), XirArgument.forObject(checkcastCounters), receiver, hub);
@@ -821,59 +824,63 @@
                 return new XirSnippet(checkCastTemplates.get(site, 0), receiver, hub);
             }
         } else {
-            XirArgument[] params = new XirArgument[(useCounters ? 1 : 0) + hints.length + (hintsExact ? 1 : 2)];
+            XirArgument[] params = new XirArgument[(useCounters ? 1 : 0) + hintsLength + (hints.exact ? 1 : 2)];
             int i = 0;
             if (useCounters) {
                 params[i++] = XirArgument.forObject(checkcastCounters);
             }
             params[i++] = receiver;
-            if (!hintsExact) {
+            if (!hints.exact) {
                 params[i++] = hub;
             }
-            for (RiResolvedType hint : hints) {
+            for (RiResolvedType hint : hints.types) {
                 params[i++] = XirArgument.forObject(((HotSpotType) hint).klassOop());
             }
-            XirTemplate template = hintsExact ? checkCastTemplates.get(site, hints.length, EXACT_HINTS) : checkCastTemplates.get(site, hints.length);
+            XirTemplate template = hints.exact ? checkCastTemplates.get(site, hintsLength, EXACT_HINTS) : checkCastTemplates.get(site, hintsLength);
             return new XirSnippet(template, params);
         }
     }
 
     @Override
-    public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiType type, RiResolvedType[] hints, boolean hintsExact) {
-        if (hints == null || hints.length == 0) {
+    public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiResolvedType type, RiTypeProfile profile) {
+        TypeCheckHints hints = new TypeCheckHints(type, profile, site.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints);
+        int hintsLength = hints.types.length;
+        if (hintsLength == 0) {
             return new XirSnippet(instanceOfTemplates.get(site, 0), object, hub);
         } else {
-            XirArgument[] params = new XirArgument[hints.length + (hintsExact ? 1 : 2)];
+            XirArgument[] params = new XirArgument[hintsLength + (hints.exact ? 1 : 2)];
             int i = 0;
             params[i++] = object;
-            if (!hintsExact) {
+            if (!hints.exact) {
                 params[i++] = hub;
             }
-            for (RiResolvedType hint : hints) {
+            for (RiResolvedType hint : hints.types) {
                 params[i++] = XirArgument.forObject(((HotSpotType) hint).klassOop());
             }
-            XirTemplate template = hintsExact ? instanceOfTemplates.get(site, hints.length, EXACT_HINTS) : instanceOfTemplates.get(site, hints.length);
+            XirTemplate template = hints.exact ? instanceOfTemplates.get(site, hintsLength, EXACT_HINTS) : instanceOfTemplates.get(site, hintsLength);
             return new XirSnippet(template, params);
         }
     }
 
     @Override
-    public XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument object, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type, RiResolvedType[] hints, boolean hintsExact) {
-        if (hints == null || hints.length == 0) {
+    public XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument object, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiResolvedType type, RiTypeProfile profile) {
+        TypeCheckHints hints = new TypeCheckHints(type, profile, site.assumptions(), GraalOptions.InstanceOfMinHintHitProbability, GraalOptions.InstanceOfMaxHints);
+        int hintsLength = hints.types.length;
+        if (hintsLength == 0) {
             return new XirSnippet(materializeInstanceOfTemplates.get(site, 0), object, hub, trueValue, falseValue);
         } else {
-            XirArgument[] params = new XirArgument[hints.length + (hintsExact ? 3 : 4)];
+            XirArgument[] params = new XirArgument[hintsLength + (hints.exact ? 3 : 4)];
             int i = 0;
             params[i++] = object;
-            if (!hintsExact) {
+            if (!hints.exact) {
                 params[i++] = hub;
             }
             params[i++] = trueValue;
             params[i++] = falseValue;
-            for (RiResolvedType hint : hints) {
+            for (RiResolvedType hint : hints.types) {
                 params[i++] = XirArgument.forObject(((HotSpotType) hint).klassOop());
             }
-            XirTemplate template = hintsExact ? materializeInstanceOfTemplates.get(site, hints.length, EXACT_HINTS) : materializeInstanceOfTemplates.get(site, hints.length);
+            XirTemplate template = hints.exact ? materializeInstanceOfTemplates.get(site, hintsLength, EXACT_HINTS) : materializeInstanceOfTemplates.get(site, hintsLength);
             return new XirSnippet(template, params);
         }
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java	Thu May 10 14:24:25 2012 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import com.oracle.graal.compiler.*;
 import com.oracle.graal.compiler.phases.*;
 import com.oracle.graal.compiler.phases.CanonicalizerPhase.IsImmutablePredicate;
 import com.oracle.graal.compiler.util.*;
@@ -35,6 +36,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
+import com.oracle.max.criutils.*;
 
 /**
  * Lowers a {@link CheckCastNode} by replacing it with the graph of a {@linkplain CheckCastSnippets checkcast snippet}.
@@ -63,19 +65,19 @@
         for (CheckCastNode node : graph.getNodes(CheckCastNode.class)) {
             ValueNode hub = node.targetClassInstruction();
             ValueNode object = node.object();
-            RiResolvedType[] hints = node.hints();
+            CiAssumptions assumptions = null;
+            TypeCheckHints hints = new TypeCheckHints(node.targetClass(), node.profile(), assumptions, GraalOptions.CheckcastMinHintHitProbability, GraalOptions.CheckcastMaxHints);
             StructuredGraph snippetGraph = (StructuredGraph) checkcast.compilerStorage().get(Graph.class);
             assert snippetGraph != null : CheckCastSnippets.class.getSimpleName() + " should be installed";
-            HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.length];
+            HotSpotKlassOop[] hintHubs = new HotSpotKlassOop[hints.types.length];
             for (int i = 0; i < hintHubs.length; i++) {
-                hintHubs[i] = ((HotSpotType) hints[i]).klassOop();
+                hintHubs[i] = ((HotSpotType) hints.types[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());
+            Debug.log("Lowering checkcast in %s: node=%s, hintsHubs=%s, exact=%b", graph, node, Arrays.toString(hints.types), hints.exact);
 
-            InliningUtil.inlineSnippet(runtime, node, (FixedWithNextNode) node.anchor(), snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(node.hintsExact()));
+            InliningUtil.inlineSnippet(runtime, node, node, snippetGraph, true, immutabilityPredicate, hub, object, hintHubsConst, CiConstant.forBoolean(hints.exact));
         }
         if (!hintHubsSet.isEmpty()) {
             Debug.log("Lowered %d checkcasts in %s ", hintHubsSet.size(), graph);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Thu May 10 14:24:25 2012 +0200
@@ -56,8 +56,8 @@
     }
 
     @Override
-    public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir) {
-        return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir) {
+    public LIRGenerator newLIRGenerator(Graph graph, FrameMap frameMap, RiResolvedMethod method, LIR lir, RiXirGenerator xir, CiAssumptions assumptions) {
+        return new AMD64LIRGenerator(graph, runtime, target, frameMap, method, lir, xir, assumptions) {
 
             @Override
             public void visitSafepointNode(SafepointNode i) {
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Thu May 10 14:24:25 2012 +0200
@@ -255,7 +255,7 @@
         FrameStateBuilder dispatchState = frameState.copy();
         dispatchState.clearStack();
 
-        BeginNode dispatchBegin = currentGraph.add(new BeginStateSplitNode());
+        BeginNode dispatchBegin = currentGraph.add(new DispatchBeginNode());
         dispatchBegin.setStateAfter(dispatchState.create(bci));
 
         if (exceptionObject == null) {
@@ -590,40 +590,15 @@
         }
     }
 
-    private static final RiResolvedType[] EMPTY_TYPE_ARRAY = new RiResolvedType[0];
-
-    private RiResolvedType[] getTypeCheckHints(RiResolvedType type, int maxHints) {
-        if (!optimisticOpts.useTypeCheckHints() || Util.isFinalClass(type)) {
-            return new RiResolvedType[] {type};
+    private RiTypeProfile getProfileForTypeCheck(RiResolvedType type) {
+        if (!optimisticOpts.useTypeCheckHints() || TypeCheckHints.isFinalClass(type)) {
+            return null;
         } else {
             RiResolvedType uniqueSubtype = type.uniqueConcreteSubtype();
             if (uniqueSubtype != null) {
-                return new RiResolvedType[] {uniqueSubtype};
+                return new RiTypeProfile(0.0D, new ProfiledType(uniqueSubtype, 1.0D));
             } else {
-                RiTypeProfile typeProfile = profilingInfo.getTypeProfile(bci());
-                if (typeProfile != null) {
-                    double notRecordedTypes = typeProfile.getNotRecordedProbability();
-                    ProfiledType[] ptypes = typeProfile.getTypes();
-                    if (notRecordedTypes < (1D - GraalOptions.CheckcastMinHintHitProbability) && ptypes != null && ptypes.length > 0) {
-                        RiResolvedType[] hints = new RiResolvedType[ptypes.length];
-                        int hintCount = 0;
-                        double totalHintProbability = 0.0d;
-                        for (ProfiledType ptype : ptypes) {
-                            RiResolvedType hint = ptype.type;
-                            if (hint.isSubtypeOf(type)) {
-                                hints[hintCount++] = hint;
-                                totalHintProbability += ptype.probability;
-                            }
-                        }
-                        if (totalHintProbability >= GraalOptions.CheckcastMinHintHitProbability) {
-                            if (hints.length == hintCount && hintCount <= maxHints) {
-                                return hints;
-                            }
-                            return Arrays.copyOf(hints, Math.min(maxHints, hintCount));
-                        }
-                    }
-                }
-                return EMPTY_TYPE_ARRAY;
+                return profilingInfo.getTypeProfile(bci());
             }
         }
     }
@@ -635,13 +610,8 @@
         if (initialized) {
             ConstantNode typeInstruction = genTypeOrDeopt(RiType.Representation.ObjectHub, type, true);
             ValueNode object = frameState.apop();
-            AnchorNode anchor = currentGraph.add(new AnchorNode());
-            append(anchor);
-            CheckCastNode checkCast;
-            RiResolvedType[] hints = getTypeCheckHints((RiResolvedType) type, GraalOptions.CheckcastMaxHints);
-            boolean hintsExact = Util.isFinalClass((RiResolvedType) type);
-            checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, hints, hintsExact));
-            append(currentGraph.add(new ValueAnchorNode(checkCast)));
+            CheckCastNode checkCast = currentGraph.add(new CheckCastNode(typeInstruction, (RiResolvedType) type, object, getProfileForTypeCheck((RiResolvedType) type)));
+            append(checkCast);
             frameState.apush(checkCast);
         } else {
             ValueNode object = frameState.apop();
@@ -657,9 +627,7 @@
         if (type instanceof RiResolvedType) {
             RiResolvedType resolvedType = (RiResolvedType) type;
             ConstantNode hub = appendConstant(resolvedType.getEncoding(RiType.Representation.ObjectHub));
-
-            RiResolvedType[] hints = getTypeCheckHints(resolvedType, GraalOptions.InstanceOfMaxHints);
-            InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, hints, Util.isFinalClass(resolvedType), false);
+            InstanceOfNode instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, getProfileForTypeCheck(resolvedType), false);
             frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph)));
         } else {
             BlockPlaceholderNode trueSucc = currentGraph.add(new BlockPlaceholderNode());
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginStateSplitNode.java	Thu May 10 14:24:25 2012 +0200
@@ -25,7 +25,7 @@
 /**
  * Base class for {@link BeginNode}s that are associated with a frame state.
  */
-public class BeginStateSplitNode extends BeginNode implements StateSplit {
+public abstract class BeginStateSplitNode extends BeginNode implements StateSplit {
 
     /**
      * A begin node has no side effect.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/DispatchBeginNode.java	Thu May 10 14:24:25 2012 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * The entry node of an exception dispatcher block.
+ */
+public class DispatchBeginNode extends BeginStateSplitNode {
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardNode.java	Thu May 10 14:24:25 2012 +0200
@@ -29,6 +29,17 @@
 import com.oracle.graal.nodes.type.*;
 import com.oracle.max.cri.ri.*;
 
+/**
+ * A guard is a node that deoptimizes based on a conditional expression. Guards are not attached to a certain frame
+ * state, they can move around freely and will always use the correct frame state when the nodes are scheduled (i.e.,
+ * the last emitted frame state). The node that is guarded has a data dependency on the guard and the guard in turn has
+ * a data dependency on the condition. A guard may only be executed if it is guaranteed that the guarded node is
+ * executed too (if no exceptions are thrown). Therefore, an {@linkplain AnchorNode anchor} is placed after a control
+ * flow split and the guard has a data dependency to the anchor. The anchor is the most distant node that is
+ * post-dominated by the guarded node and the guard can be scheduled anywhere between those two nodes. This ensures
+ * maximum flexibility for the guard node and guarantees that deoptimization occurs only if the control flow would have
+ * reached the guarded node (without taking exceptions into account).
+ */
 public final class GuardNode extends FloatingNode implements Canonicalizable, LIRLowerable, TypeFeedbackProvider, Node.IterableNodeType {
 
     @Input private BooleanNode condition;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Thu May 10 14:24:25 2012 +0200
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * The start node of a graph.
+ */
+public class StartNode extends BeginStateSplitNode {
+
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java	Thu May 10 14:24:25 2012 +0200
@@ -64,7 +64,7 @@
 
     private StructuredGraph(String name, RiResolvedMethod method, long graphId) {
         super(name);
-        this.start = add(new BeginStateSplitNode());
+        this.start = add(new StartNode());
         this.method = method;
         this.graphId = graphId;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Thu May 10 14:24:25 2012 +0200
@@ -25,7 +25,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.spi.types.*;
 import com.oracle.graal.nodes.type.*;
@@ -33,32 +32,31 @@
 import com.oracle.max.cri.ri.*;
 
 /**
- * The {@code CheckCastNode} represents a {@link Bytecodes#CHECKCAST}.
- *
- * The {@link #targetClass()} of a CheckCastNode can be null for array store checks!
+ * Implements a type check that results in a {@link ClassCastException} if it fails.
  */
-public final class CheckCastNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable {
+public final class CheckCastNode extends FixedWithNextNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType, TypeFeedbackProvider, TypeCanonicalizable {
 
-    @Input(notDataflow = true) protected final FixedNode anchor;
-
-    public FixedNode anchor() {
-        return anchor;
-    }
+    @Input private ValueNode object;
+    @Input private ValueNode targetClassInstruction;
+    private final RiResolvedType targetClass;
+    private final RiTypeProfile profile;
 
     /**
      * Creates a new CheckCast instruction.
-     *
      * @param targetClassInstruction the instruction which produces the class which is being cast to
      * @param targetClass the class being cast to
      * @param object the instruction producing the object
      */
-    public CheckCastNode(FixedNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) {
-        this(anchor, targetClassInstruction, targetClass, object, EMPTY_HINTS, false);
+    public CheckCastNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) {
+        this(targetClassInstruction, targetClass, object, null);
     }
 
-    public CheckCastNode(FixedNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiResolvedType[] hints, boolean hintsExact) {
-        super(targetClassInstruction, targetClass, object, hints, hintsExact, targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass));
-        this.anchor = anchor;
+    public CheckCastNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile) {
+        super(targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass));
+        this.targetClassInstruction = targetClassInstruction;
+        this.targetClass = targetClass;
+        this.object = object;
+        this.profile = profile;
     }
 
     @Override
@@ -71,10 +69,8 @@
         assert object() != null : this;
 
         RiResolvedType objectDeclaredType = object().declaredType();
-        RiResolvedType targetClass = targetClass();
         if (objectDeclaredType != null && targetClass != null && objectDeclaredType.isSubtypeOf(targetClass)) {
             // we don't have to check for null types here because they will also pass the checkcast.
-            freeAnchor();
             return object();
         }
 
@@ -82,33 +78,12 @@
         if (constant != null) {
             assert constant.kind == CiKind.Object;
             if (constant.isNull()) {
-                freeAnchor();
                 return object();
             }
         }
-
-        if (tool.assumptions() != null && hints() != null && targetClass() != null) {
-            if (!hintsExact() && hints().length == 1 && hints()[0] == targetClass().uniqueConcreteSubtype()) {
-                tool.assumptions().recordConcreteSubtype(targetClass(), hints()[0]);
-                return graph().unique(new CheckCastNode(anchor, targetClassInstruction(), targetClass(), object(), hints(), true));
-            }
-        }
         return this;
     }
 
-    // TODO (thomaswue): Find a better way to handle anchors.
-    private void freeAnchor() {
-        ValueAnchorNode anchorUsage = usages().filter(ValueAnchorNode.class).first();
-        if (anchorUsage != null) {
-            anchorUsage.replaceFirstInput(this, null);
-        }
-    }
-
-    @Override
-    public BooleanNode negate() {
-        throw new Error("A CheckCast does not produce a boolean value, so it should actually not be a subclass of BooleanNode");
-    }
-
     @Override
     public void typeFeedback(TypeFeedbackTool tool) {
         if (targetClass() != null) {
@@ -128,4 +103,27 @@
         }
         return null;
     }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode targetClassInstruction() {
+        return targetClassInstruction;
+    }
+
+    /**
+     * Gets the target class, i.e. the class being cast to, or the class being tested against.
+     * This may be null in the case where the type being tested is dynamically loaded such as
+     * when checking an object array store.
+     *
+     * @return the target class or null if not known
+     */
+    public RiResolvedType targetClass() {
+        return targetClass;
+    }
+
+    public RiTypeProfile profile() {
+        return profile;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Thu May 10 14:24:25 2012 +0200
@@ -33,9 +33,13 @@
 /**
  * The {@code InstanceOfNode} represents an instanceof test.
  */
-public final class InstanceOfNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable {
+public final class InstanceOfNode extends BooleanNode implements Canonicalizable, LIRLowerable, ConditionalTypeFeedbackProvider, TypeCanonicalizable {
 
     private final boolean negated;
+    @Input private ValueNode object;
+    @Input private ValueNode targetClassInstruction;
+    private final RiResolvedType targetClass;
+    private final RiTypeProfile profile;
 
     public boolean negated() {
         return negated;
@@ -49,11 +53,15 @@
      * @param object the instruction producing the object input to this instruction
      */
     public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, boolean negated) {
-        this(targetClassInstruction, targetClass, object, EMPTY_HINTS, false, negated);
+        this(targetClassInstruction, targetClass, object, null, negated);
     }
 
-    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiResolvedType[] hints, boolean hintsExact, boolean negated) {
-        super(targetClassInstruction, targetClass, object, hints, hintsExact, StampFactory.illegal());
+    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile, boolean negated) {
+        super(StampFactory.illegal());
+        this.targetClassInstruction = targetClassInstruction;
+        this.targetClass = targetClass;
+        this.object = object;
+        this.profile = profile;
         this.negated = negated;
         assert targetClass != null;
     }
@@ -112,18 +120,12 @@
                 assert false : "non-null constants are always expected to provide an exactType";
             }
         }
-        if (tool.assumptions() != null && hints() != null && targetClass() != null) {
-            if (!hintsExact() && hints().length == 1 && hints()[0] == targetClass().uniqueConcreteSubtype()) {
-                tool.assumptions().recordConcreteSubtype(targetClass(), hints()[0]);
-                return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), hints(), true, negated));
-            }
-        }
         return this;
     }
 
     @Override
     public BooleanNode negate() {
-        return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), hints(), hintsExact(), !negated));
+        return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), profile(), !negated));
     }
 
     @Override
@@ -161,4 +163,24 @@
         }
         return null;
     }
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ValueNode targetClassInstruction() {
+        return targetClassInstruction;
+    }
+
+    /**
+     * Gets the target class, i.e. the class being cast to, or the class being tested against.
+     * @return the target class
+     */
+    public RiResolvedType targetClass() {
+        return targetClass;
+    }
+
+    public RiTypeProfile profile() {
+        return profile;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Wed May 09 12:11:36 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,80 +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.java;
-
-import com.oracle.max.cri.ri.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * The {@code TypeCheckNode} is the base class of casts and instanceof tests.
- */
-public abstract class TypeCheckNode extends BooleanNode {
-
-    protected static final RiResolvedType[] EMPTY_HINTS = new RiResolvedType[0];
-    @Input private ValueNode object;
-    @Input private ValueNode targetClassInstruction;
-    private final RiResolvedType targetClass;
-    private final RiResolvedType[] hints;
-    private final boolean hintsExact;
-
-    /**
-     * Creates a new TypeCheckNode.
-     * @param targetClassInstruction the instruction which produces the class which is being cast to or checked against
-     * @param targetClass the class that is being casted to or checked against
-     * @param object the node which produces the object
-     * @param kind the result type of this node
-     */
-    public TypeCheckNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiResolvedType[] hints, boolean hintsExact, Stamp stamp) {
-        super(stamp);
-        this.targetClassInstruction = targetClassInstruction;
-        this.targetClass = targetClass;
-        this.object = object;
-        this.hints = hints;
-        this.hintsExact = hintsExact;
-    }
-
-    public ValueNode object() {
-        return object;
-    }
-
-    public ValueNode targetClassInstruction() {
-        return targetClassInstruction;
-    }
-
-    /**
-     * Gets the target class, i.e. the class being cast to, or the class being tested against.
-     * @return the target class
-     */
-    public RiResolvedType targetClass() {
-        return targetClass;
-    }
-
-    public RiResolvedType[] hints() {
-        return hints;
-    }
-
-    public boolean hintsExact() {
-        return hintsExact;
-    }
-}
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Thu May 10 14:24:25 2012 +0200
@@ -30,6 +30,7 @@
 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.*;
 
 public class LowerCheckCastTest extends GraphTest {
 
@@ -41,78 +42,77 @@
         asStringExt("0");
     }
 
-    private RiCompiledMethod compile(String name, Class[] hintClasses, boolean exact) {
+    private RiCompiledMethod compile(String name, RiTypeProfile profile) {
         //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);
+        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 static final boolean EXACT = true;
-    private static final boolean NOT_EXACT = false;
-
-    private static Class[] hints(Class... classes) {
-        return classes;
+    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, Class[] hints, boolean exact, Object expected, Object... args) {
-        RiCompiledMethod compiledMethod = compile(name, hints, exact);
+    private void test(String name, RiTypeProfile profile, Object expected, Object... args) {
+        RiCompiledMethod compiledMethod = compile(name, profile);
         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("asNumber",    profile(),                        111, 111);
+        test("asNumber",    profile(Integer.class),           111, 111);
+        test("asNumber",    profile(Long.class, Short.class), 111, 111);
+        test("asNumberExt", profile(),                        121, 111);
+        test("asNumberExt", profile(Integer.class),           121, 111);
+        test("asNumberExt", profile(Long.class, Short.class), 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("asString",    profile(),             "111", "111");
+        test("asString",    profile(String.class), "111", "111");
+        test("asString",    profile(String.class), "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("asStringExt", profile(),             "#111", "111");
+        test("asStringExt", profile(String.class), "#111", "111");
+        test("asStringExt", profile(String.class), "#111", "111");
     }
 
     @Test(expected = ClassCastException.class)
     public void test3() {
-        test("asNumber", hints(), NOT_EXACT, 111, "111");
+        test("asNumber", profile(), 111, "111");
     }
 
     @Test(expected = ClassCastException.class)
     public void test4() {
-        test("asString", hints(String.class), EXACT, "111", 111);
+        test("asString", profile(String.class), "111", 111);
     }
 
     @Test(expected = ClassCastException.class)
     public void test5() {
-        test("asNumberExt", hints(), NOT_EXACT, 111, "111");
+        test("asNumberExt", profile(), 111, "111");
     }
 
     @Test(expected = ClassCastException.class)
     public void test6() {
-        test("asStringExt", hints(String.class), EXACT, "111", 111);
+        test("asStringExt", profile(String.class), "111", 111);
     }
 
     public static Number asNumber(Object o) {
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java	Thu May 10 14:24:25 2012 +0200
@@ -43,6 +43,8 @@
         public final double probability;
 
         public ProfiledType(RiResolvedType type, double probability) {
+            assert type != null;
+            assert probability >= 0.0D && probability <= 1.0D;
             this.type = type;
             this.probability = probability;
         }
@@ -73,7 +75,7 @@
         return true;
     }
 
-    public RiTypeProfile(ProfiledType[] ptypes, double notRecordedProbability) {
+    public RiTypeProfile(double notRecordedProbability, ProfiledType... ptypes) {
         this.ptypes = ptypes;
         this.notRecordedProbability = notRecordedProbability;
         assert isSorted(ptypes);
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Thu May 10 14:24:25 2012 +0200
@@ -49,11 +49,11 @@
 
     XirSnippet genNewMultiArray(XirSite site, XirArgument[] lengths, RiType type);
 
-    XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiResolvedType[] hints, boolean hintsExact);
+    XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiTypeProfile profile);
 
-    XirSnippet genInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, RiType type, RiResolvedType[] hints, boolean hintsExact);
+    XirSnippet genInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, RiResolvedType type, RiTypeProfile profile);
 
-    XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type, RiResolvedType[] hints, boolean hintsExact);
+    XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiResolvedType type, RiTypeProfile profile);
 
     /**
      * Generates code that checks that the {@linkplain Representation#ObjectHub hub} of
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java	Wed May 09 12:11:36 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java	Thu May 10 14:24:25 2012 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.max.cri.xir;
 
+import com.oracle.max.cri.ci.*;
+
 /**
  * Encapsulates the notion of a site where XIR can be supplied. It is supplied to the {@link RiXirGenerator} by the
  * compiler for each place where XIR can be generated. This interface allows a number of queries, including the
@@ -65,4 +67,10 @@
      * @return {@code true} if an array store check is required
      */
     boolean requiresArrayStoreCheck();
+
+    /**
+     * The object for recording speculations made during compilation.
+     * May be null.
+     */
+    CiAssumptions assumptions();
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.criutils/src/com/oracle/max/criutils/TypeCheckHints.java	Thu May 10 14:24:25 2012 +0200
@@ -0,0 +1,111 @@
+/*
+ * 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.max.criutils;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.cri.ri.RiTypeProfile.ProfiledType;
+
+/**
+ * Utility for deriving hint types for a type check instruction (e.g. checkcast or instanceof)
+ * based on the target type of the check and any profiling information available for the instruction.
+ */
+public class TypeCheckHints {
+
+    private static final RiResolvedType[] NO_TYPES = {};
+
+    /**
+     * If true, then {@link #types} contains the only possible type that could pass the type check
+     * because the target of the type check is a final class or has been speculated to be a final class.
+     */
+    public final boolean exact;
+
+    /**
+     * The most likely types that the type check instruction will see.
+     */
+    public final RiResolvedType[] types;
+
+    /**
+     * Derives hint information for use when generating the code for a type check instruction.
+     *
+     * @param type the target type of the type check
+     * @param profile the profiling information available for the instruction (if any)
+     * @param assumptions the object in which speculations are recorded. This is null if speculations are not supported.
+     * @param minHintHitProbability if the probability that the type check will hit one the profiled types (up to
+     *            {@code maxHints}) is below this value, then {@link #types} will be null
+     * @param maxHints the maximum length of {@link #types}
+     */
+    public TypeCheckHints(RiResolvedType type, RiTypeProfile profile, CiAssumptions assumptions, double minHintHitProbability, int maxHints) {
+        if (type != null && isFinalClass(type)) {
+            types = new RiResolvedType[] {type};
+            exact = true;
+        } else {
+            RiResolvedType uniqueSubtype = type == null ? null : type.uniqueConcreteSubtype();
+            if (uniqueSubtype != null) {
+                types = new RiResolvedType[] {uniqueSubtype};
+                if (assumptions != null) {
+                    assumptions.recordConcreteSubtype(type, uniqueSubtype);
+                    exact = true;
+                } else {
+                    exact = false;
+                }
+            } else {
+                exact = false;
+                RiResolvedType[] hintTypes = NO_TYPES;
+                RiTypeProfile typeProfile = profile;
+                if (typeProfile != null) {
+                    double notRecordedTypes = typeProfile.getNotRecordedProbability();
+                    ProfiledType[] ptypes = typeProfile.getTypes();
+                    if (notRecordedTypes < (1D - minHintHitProbability) && ptypes != null && ptypes.length > 0) {
+                        hintTypes = new RiResolvedType[ptypes.length];
+                        int hintCount = 0;
+                        double totalHintProbability = 0.0d;
+                        for (ProfiledType ptype : ptypes) {
+                            RiResolvedType hint = ptype.type;
+                            if (type != null && hint.isSubtypeOf(type)) {
+                                hintTypes[hintCount++] = hint;
+                                totalHintProbability += ptype.probability;
+                            }
+                        }
+                        if (totalHintProbability >= minHintHitProbability) {
+                            if (hintTypes.length != hintCount || hintCount > maxHints) {
+                                hintTypes = Arrays.copyOf(hintTypes, Math.min(maxHints, hintCount));
+                            }
+                        } else {
+                            hintTypes = NO_TYPES;
+                        }
+
+                    }
+                }
+                this.types = hintTypes;
+            }
+        }
+    }
+
+    public static boolean isFinalClass(RiResolvedType type) {
+        return Modifier.isFinal(type.accessFlags()) || (type.isArrayClass() && Modifier.isFinal(type.componentType().accessFlags()));
+    }
+}