changeset 5369:2e9a5365dfb0

moved conversion of type profiles into hints for type check instructions from front end to lowering phase
author Doug Simon <doug.simon@oracle.com>
date Wed, 09 May 2012 22:21:58 +0200
parents a4218dd1b157
children 5229911d3970
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java graal/com.oracle.max.criutils/src/com/oracle/max/criutils/TypeCheckHints.java
diffstat 19 files changed, 254 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed May 09 22:21:58 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>() {
@@ -232,9 +232,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 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Wed May 09 22:21:58 2012 +0200
@@ -245,6 +245,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 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/gen/LIRGenerator.java	Wed May 09 22:21:58 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/target/Backend.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/Backend.java	Wed May 09 22:21:58 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 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/target/amd64/AMD64LIRGenerator.java	Wed May 09 22:21:58 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/util/Util.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/util/Util.java	Wed May 09 22:21:58 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/ri/HotSpotMethodData.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotMethodData.java	Wed May 09 22:21:58 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/HotSpotXirGenerator.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/ri/HotSpotXirGenerator.java	Wed May 09 22:21:58 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 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/snippets/LowerCheckCastPhase.java	Wed May 09 22:21:58 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, (FixedWithNextNode) node.anchor(), 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 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/target/amd64/HotSpotAMD64Backend.java	Wed May 09 22:21:58 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 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java	Wed May 09 22:21:58 2012 +0200
@@ -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());
             }
         }
     }
@@ -638,9 +613,7 @@
             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));
+            checkCast = currentGraph.unique(new CheckCastNode(anchor, typeInstruction, (RiResolvedType) type, object, getProfileForTypeCheck((RiResolvedType) type)));
             append(currentGraph.add(new ValueAnchorNode(checkCast)));
             frameState.apush(checkCast);
         } else {
@@ -657,9 +630,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/java/CheckCastNode.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Wed May 09 22:21:58 2012 +0200
@@ -53,11 +53,11 @@
      * @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);
+        this(anchor, 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));
+    public CheckCastNode(FixedNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile) {
+        super(targetClassInstruction, targetClass, object, profile, targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass));
         this.anchor = anchor;
     }
 
@@ -87,12 +87,12 @@
             }
         }
 
-        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));
-            }
-        }
+//        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;
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Wed May 09 22:21:58 2012 +0200
@@ -49,11 +49,11 @@
      * @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(targetClassInstruction, targetClass, object, profile, StampFactory.illegal());
         this.negated = negated;
         assert targetClass != null;
     }
@@ -112,18 +112,18 @@
                 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));
-            }
-        }
+//        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
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/TypeCheckNode.java	Wed May 09 22:21:58 2012 +0200
@@ -35,23 +35,22 @@
     @Input private ValueNode object;
     @Input private ValueNode targetClassInstruction;
     private final RiResolvedType targetClass;
-    private final RiResolvedType[] hints;
-    private final boolean hintsExact;
+    private final RiTypeProfile profile;
 
     /**
      * 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) {
+    public TypeCheckNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, RiTypeProfile profile, Stamp stamp) {
         super(stamp);
         this.targetClassInstruction = targetClassInstruction;
         this.targetClass = targetClass;
         this.object = object;
-        this.hints = hints;
-        this.hintsExact = hintsExact;
+        this.profile = profile;
     }
 
     public ValueNode object() {
@@ -70,11 +69,7 @@
         return targetClass;
     }
 
-    public RiResolvedType[] hints() {
-        return hints;
-    }
-
-    public boolean hintsExact() {
-        return hintsExact;
+    public RiTypeProfile profile() {
+        return profile;
     }
 }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Wed May 09 16:39:52 2012 +0200
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/LowerCheckCastTest.java	Wed May 09 22:21:58 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,20 +42,15 @@
         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));
+        CheckCastNode ccnNew = graph.add(new CheckCastNode(ccn.anchor(), ccn.targetClassInstruction(), ccn.targetClass(), ccn.object(), profile));
         graph.replaceFloating(ccn, ccnNew);
 
         final RiResolvedMethod riMethod = runtime.getRiMethod(method);
@@ -62,57 +58,61 @@
         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 16:39:52 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/ri/RiTypeProfile.java	Wed May 09 22:21:58 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 16:39:52 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Wed May 09 22:21:58 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 16:39:52 2012 +0200
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/XirSite.java	Wed May 09 22:21:58 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	Wed May 09 22:21:58 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()));
+    }
+}