changeset 4430:be4914c1c799

add hints to InstanceOfNode and CheckCastNode
author Lukas Stadler <lukas.stadler@jku.at>
date Fri, 03 Feb 2012 10:17:33 +0100
parents 730fab2457b8
children 73f56093d824
files graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/TemplateFlag.java graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/CheckCastNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/InstanceOfNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/TypeCheckNode.java
diffstat 9 files changed, 278 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Fri Feb 03 10:17:33 2012 +0100
@@ -77,11 +77,11 @@
 
     XirSnippet genNewMultiArray(XirSite site, XirArgument[] lengths, RiType type);
 
-    XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type);
+    XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type, XirArgument[] hintHubs, boolean hintsExact);
 
-    XirSnippet genInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, RiType type);
+    XirSnippet genInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, RiType type, XirArgument[] hintHubs, boolean hintsExact);
 
-    XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type);
+    XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument receiver, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type, XirArgument[] hintHubs, boolean hintsExact);
 
     XirSnippet genArrayLoad(XirSite site, XirArgument array, XirArgument index, CiKind elementKind, RiType elementType);
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Feb 03 10:17:33 2012 +0100
@@ -126,6 +126,7 @@
     public static int     MatureInvocationCount              = 100;
     public static boolean GenSafepoints                      = true;
     public static boolean GenLoopSafepoints                  = true;
+    public static boolean UseInstanceOfHints                 = true;
 
     public static boolean GenAssertionCode                   = ____;
     public static boolean AlignCallsForPatching              = true;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Feb 03 10:17:33 2012 +0100
@@ -480,12 +480,27 @@
 
     @Override
     public void visitCheckCast(CheckCastNode x) {
-        XirSnippet snippet = xir.genCheckCast(site(x), toXirArgument(x.object()), toXirArgument(x.targetClassInstruction()), x.targetClass());
+        XirArgument[] hints = getTypeCheckHints(x);
+        XirSnippet snippet = xir.genCheckCast(site(x), toXirArgument(x.object()), toXirArgument(x.targetClassInstruction()), x.targetClass(), hints, x.hintsExact());
         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()));
     }
 
+    private XirArgument[] getTypeCheckHints(TypeCheckNode x) {
+        XirArgument[] hints;
+        if (!GraalOptions.UseInstanceOfHints || x.hints() == null || x.hints().length == 0) {
+            hints = new XirArgument[0];
+        } else {
+            assert x.hints().length == x.hintInstructions().size();
+            hints = new XirArgument[x.hints().length];
+            for (int i = 0; i < x.hints().length; i++) {
+                hints[i] = toXirArgument(x.hintInstructions().get(i));
+            }
+        }
+        return hints;
+    }
+
     @Override
     public void visitMonitorEnter(MonitorEnterNode x) {
         CiStackSlot lockData = frameMap.allocateStackBlock(runtime.sizeOfLockData(), false);
@@ -739,8 +754,9 @@
     }
 
     private void emitInstanceOfBranch(InstanceOfNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+        XirArgument[] hints = getTypeCheckHints(x);
         XirArgument obj = toXirArgument(x.object());
-        XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass());
+        XirSnippet snippet = xir.genInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), x.targetClass(), hints, x.hintsExact());
         emitXir(snippet, x, info, null, false, x.negated() ? falseSuccessor : trueSuccessor, x.negated() ? trueSuccessor : falseSuccessor);
     }
 
@@ -782,10 +798,11 @@
     }
 
     private Variable emitInstanceOfConditional(InstanceOfNode x, CiValue trueValue, CiValue falseValue) {
+        XirArgument[] hints = getTypeCheckHints(x);
         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), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass());
+        XirSnippet snippet = xir.genMaterializeInstanceOf(site(x), obj, toXirArgument(x.targetClassInstruction()), trueArg, falseArg, x.targetClass(), hints, x.hintsExact());
         return (Variable) emitXir(snippet, null, null, false);
     }
 
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java	Fri Feb 03 10:17:33 2012 +0100
@@ -637,10 +637,10 @@
         }
     };
 
-    private SimpleTemplates checkCastTemplates = new SimpleTemplates(NULL_CHECK) {
+    private IndexTemplates checkCastTemplates = new IndexTemplates(NULL_CHECK, EXACT_HINTS) {
 
         @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
+        protected XirTemplate create(CiXirAssembler asm, long flags, int hintCount) {
             asm.restart(CiKind.Void);
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
             final XirOperand hub;
@@ -657,14 +657,34 @@
             }
 
             asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
-            // if we get an exact match: succeed immediately
-            asm.jneq(slowPath, objHub, hub);
-            asm.bindInline(end);
+            if (hintCount == 0) {
+                assert !is(EXACT_HINTS, flags);
+                checkSubtype(asm, objHub, objHub, hub);
+                asm.jeq(slowPath, objHub, asm.o(null));
+                asm.bindInline(end);
 
-            // -- out of line -------------------------------------------------------
-            asm.bindOutOfLine(slowPath);
-            checkSubtype(asm, objHub, objHub, hub);
-            asm.jneq(end, objHub, asm.o(null));
+                // -- out of line -------------------------------------------------------
+                asm.bindOutOfLine(slowPath);
+            } else {
+                // if we get an exact match: succeed immediately
+                for (int i = 0; i < hintCount; i++) {
+                    XirParameter hintHub = asm.createInputParameter("hintHub" + i, CiKind.Object);
+                    if (i < hintCount - 1) {
+                        asm.jeq(end, objHub, hintHub);
+                    } else {
+                        asm.jneq(slowPath, objHub, hintHub);
+                    }
+                }
+                asm.bindInline(end);
+
+                // -- out of line -------------------------------------------------------
+                asm.bindOutOfLine(slowPath);
+                if (!is(EXACT_HINTS, flags)) {
+                    checkSubtype(asm, objHub, objHub, hub);
+                    asm.jneq(end, objHub, asm.o(null));
+                }
+            }
+
             XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10);
             asm.mov(scratch, wordConst(asm, 2));
 
@@ -675,10 +695,10 @@
         }
     };
 
-    private SimpleTemplates instanceOfTemplates = new SimpleTemplates(NULL_CHECK) {
+    private IndexTemplates instanceOfTemplates = new IndexTemplates(NULL_CHECK, EXACT_HINTS) {
 
         @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
+        protected XirTemplate create(CiXirAssembler asm, long flags, int hintCount) {
             asm.restart(CiKind.Void);
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
             final XirOperand hub;
@@ -686,7 +706,6 @@
 
             XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
 
-            XirLabel slowPath = asm.createOutOfLineLabel("slow path");
             XirLabel trueSucc = asm.createInlineLabel(XirLabel.TrueSuccessor);
             XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor);
 
@@ -696,24 +715,48 @@
             }
 
             asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
-            // if we get an exact match: succeed immediately
-            asm.jeq(trueSucc, objHub, hub);
-            asm.jmp(slowPath);
+            if (hintCount == 0) {
+                assert !is(EXACT_HINTS, flags);
+                checkSubtype(asm, objHub, objHub, hub);
+                asm.jeq(falseSucc, objHub, asm.o(null));
+                asm.jmp(trueSucc);
+            } else {
+                XirLabel slowPath = null;
 
-            // -- out of line -------------------------------------------------------
-            asm.bindOutOfLine(slowPath);
-            checkSubtype(asm, objHub, objHub, hub);
-            asm.jeq(falseSucc, objHub, asm.o(null));
-            asm.jmp(trueSucc);
+                // if we get an exact match: succeed immediately
+                for (int i = 0; i < hintCount; i++) {
+                    XirParameter hintHub = asm.createInputParameter("hintHub" + i, CiKind.Object);
+                    if (i < hintCount - 1) {
+                        asm.jeq(trueSucc, objHub, hintHub);
+                    } else {
+                        if (is(EXACT_HINTS, flags)) {
+                            asm.jneq(falseSucc, objHub, hintHub);
+                            asm.jmp(trueSucc);
+                        } else {
+                            slowPath = asm.createOutOfLineLabel("slow path");
+                            asm.jneq(slowPath, objHub, hintHub);
+                            asm.jmp(trueSucc);
+                        }
+                    }
+                }
+
+                // -- out of line -------------------------------------------------------
+                if (slowPath != null) {
+                    asm.bindOutOfLine(slowPath);
+                    checkSubtype(asm, objHub, objHub, hub);
+                    asm.jeq(falseSucc, objHub, asm.o(null));
+                    asm.jmp(trueSucc);
+                }
+            }
 
             return asm.finishTemplate("instanceof");
         }
     };
 
-    private SimpleTemplates materializeInstanceOfTemplates = new SimpleTemplates(NULL_CHECK) {
+    private IndexTemplates materializeInstanceOfTemplates = new IndexTemplates(NULL_CHECK, EXACT_HINTS) {
 
         @Override
-        protected XirTemplate create(CiXirAssembler asm, long flags) {
+        protected XirTemplate create(CiXirAssembler asm, long flags, int hintCount) {
             XirOperand result = asm.restart(CiKind.Int);
             XirParameter object = asm.createInputParameter("object", CiKind.Object);
             final XirOperand hub;
@@ -723,10 +766,8 @@
 
             XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
 
-            XirLabel slowPath = asm.createOutOfLineLabel("slow path");
-            XirLabel trueSucc = asm.createInlineLabel("ok");
+            XirLabel end = asm.createInlineLabel("end");
             XirLabel falseSucc = asm.createInlineLabel("ko");
-            XirLabel end = asm.createInlineLabel("end");
 
             if (is(NULL_CHECK, flags)) {
                 // null isn't "instanceof" anything
@@ -734,22 +775,45 @@
             }
 
             asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
-            // if we get an exact match: succeed immediately
-            asm.jeq(trueSucc, objHub, hub);
-            asm.jmp(slowPath);
+            asm.mov(result, trueValue);
+
+            if (hintCount == 0) {
+                assert !is(EXACT_HINTS, flags);
+                checkSubtype(asm, objHub, objHub, hub);
+                asm.jneq(end, objHub, asm.o(null));
+                asm.bindInline(falseSucc);
+                asm.mov(result, falseValue);
+                asm.bindInline(end);
+            } else {
+                XirLabel slowPath = null;
 
-            asm.bindInline(trueSucc);
-            asm.mov(result, trueValue);
-            asm.jmp(end);
-            asm.bindInline(falseSucc);
-            asm.mov(result, falseValue);
-            asm.bindInline(end);
+                // if we get an exact match: succeed immediately
+                for (int i = 0; i < hintCount; i++) {
+                    XirParameter hintHub = asm.createInputParameter("hintHub" + i, CiKind.Object);
+                    if (i < hintCount - 1) {
+                        asm.jeq(end, objHub, hintHub);
+                    } else {
+                        if (is(EXACT_HINTS, flags)) {
+                            asm.jeq(end, objHub, hintHub);
+                        } else {
+                            slowPath = asm.createOutOfLineLabel("slow path");
+                            asm.jeq(end, objHub, hintHub);
+                            asm.jmp(slowPath);
+                        }
+                    }
+                }
+                asm.bindInline(falseSucc);
+                asm.mov(result, falseValue);
+                asm.bindInline(end);
 
-            // -- out of line -------------------------------------------------------
-            asm.bindOutOfLine(slowPath);
-            checkSubtype(asm, objHub, objHub, hub);
-            asm.jeq(falseSucc, objHub, asm.o(null));
-            asm.jmp(trueSucc);
+                // -- out of line -------------------------------------------------------
+                if (slowPath != null) {
+                    asm.bindOutOfLine(slowPath);
+                    checkSubtype(asm, objHub, objHub, hub);
+                    asm.jeq(falseSucc, objHub, asm.o(null));
+                    asm.jmp(end);
+                }
+            }
 
             return asm.finishTemplate("instanceof");
         }
@@ -1253,18 +1317,56 @@
     }
 
     @Override
-    public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type) {
-        return new XirSnippet(checkCastTemplates.get(site), receiver, hub);
+    public XirSnippet genCheckCast(XirSite site, XirArgument receiver, XirArgument hub, RiType type, XirArgument[] hintHubs, boolean hintsExact) {
+        System.out.print(hintsExact ? "+" : "-");
+        if (hintHubs == null || hintHubs.length == 0) {
+            return new XirSnippet(checkCastTemplates.get(site, 0), receiver, hub);
+        } else {
+            XirArgument[] params = new XirArgument[hintHubs.length + 2];
+            params[0] = receiver;
+            params[1] = hub;
+            for (int i = 0; i < hintHubs.length; i++) {
+                params[i + 2] = hintHubs[i];
+            }
+            XirTemplate template = hintsExact ? checkCastTemplates.get(site, hintHubs.length, EXACT_HINTS) : checkCastTemplates.get(site, hintHubs.length);
+            return new XirSnippet(template, params);
+        }
     }
 
     @Override
-    public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiType type) {
-        return new XirSnippet(instanceOfTemplates.get(site), object, hub);
+    public XirSnippet genInstanceOf(XirSite site, XirArgument object, XirArgument hub, RiType type, XirArgument[] hintHubs, boolean hintsExact) {
+        System.out.print(hintsExact ? "+" : "-");
+        if (hintHubs == null || hintHubs.length == 0) {
+            return new XirSnippet(instanceOfTemplates.get(site, 0), object, hub);
+        } else {
+            XirArgument[] params = new XirArgument[hintHubs.length + 2];
+            params[0] = object;
+            params[1] = hub;
+            for (int i = 0; i < hintHubs.length; i++) {
+                params[i + 2] = hintHubs[i];
+            }
+            XirTemplate template = hintsExact ? instanceOfTemplates.get(site, hintHubs.length, EXACT_HINTS) : instanceOfTemplates.get(site, hintHubs.length);
+            return new XirSnippet(template, params);
+        }
     }
 
     @Override
-    public XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument object, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type) {
-        return new XirSnippet(materializeInstanceOfTemplates.get(site), object, hub, trueValue, falseValue);
+    public XirSnippet genMaterializeInstanceOf(XirSite site, XirArgument object, XirArgument hub, XirArgument trueValue, XirArgument falseValue, RiType type, XirArgument[] hintHubs, boolean hintsExact) {
+        System.out.print(hintsExact ? "+" : "-");
+        if (hintHubs == null || hintHubs.length == 0) {
+            return new XirSnippet(materializeInstanceOfTemplates.get(site, 0), object, hub, trueValue, falseValue);
+        } else {
+            XirArgument[] params = new XirArgument[hintHubs.length + 4];
+            params[0] = object;
+            params[1] = hub;
+            params[2] = trueValue;
+            params[3] = falseValue;
+            for (int i = 0; i < hintHubs.length; i++) {
+                params[i + 4] = hintHubs[i];
+            }
+            XirTemplate template = hintsExact ? materializeInstanceOfTemplates.get(site, hintHubs.length, EXACT_HINTS) : materializeInstanceOfTemplates.get(site, hintHubs.length);
+            return new XirSnippet(template, params);
+        }
     }
 
     @Override
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/TemplateFlag.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/TemplateFlag.java	Fri Feb 03 10:17:33 2012 +0100
@@ -23,7 +23,7 @@
 package com.oracle.max.graal.hotspot.ri;
 
 enum TemplateFlag {
-    NULL_CHECK, READ_BARRIER, WRITE_BARRIER, STORE_CHECK, BOUNDS_CHECK, GIVEN_LENGTH, INPUTS_DIFFERENT, INPUTS_SAME, STATIC_METHOD, SYNCHRONIZED;
+    NULL_CHECK, READ_BARRIER, WRITE_BARRIER, STORE_CHECK, BOUNDS_CHECK, GIVEN_LENGTH, INPUTS_DIFFERENT, INPUTS_SAME, STATIC_METHOD, SYNCHRONIZED, EXACT_HINTS;
 
     private static final long FIRST_FLAG = 0x0000000100000000L;
     public static final long FLAGS_MASK = 0x0000FFFF00000000L;
--- a/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.java/src/com/oracle/max/graal/java/GraphBuilderPhase.java	Fri Feb 03 10:17:33 2012 +0100
@@ -711,8 +711,43 @@
         RiType type = lookupType(cpi, INSTANCEOF);
         ValueNode object = frameState.apop();
         if (type instanceof RiResolvedType) {
-            ConstantNode hub = appendConstant(((RiResolvedType) type).getEncoding(RiType.Representation.ObjectHub));
-            frameState.ipush(append(MaterializeNode.create(currentGraph.unique(new InstanceOfNode(hub, (RiResolvedType) type, object, false)), currentGraph)));
+            RiResolvedType resolvedType = (RiResolvedType) type;
+            ConstantNode hub = appendConstant(resolvedType.getEncoding(RiType.Representation.ObjectHub));
+
+            final InstanceOfNode instanceOfNode;
+            if (!GraalOptions.UseInstanceOfHints) {
+                instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, false);
+            } else {
+                if (Modifier.isFinal(resolvedType.accessFlags()) || resolvedType.isArrayClass()) {
+                    instanceOfNode = new InstanceOfNode(hub, resolvedType, object, Collections.singletonList(hub), new RiResolvedType[] {resolvedType}, true, false);
+                } else {
+                    RiResolvedType uniqueSubtype = resolvedType.uniqueConcreteSubtype();
+                    if (uniqueSubtype != null) {
+//                        TTY.println("unique concrete subtype: " + uniqueSubtype);
+                        ConstantNode subTypeHub = appendConstant(uniqueSubtype.getEncoding(RiType.Representation.ObjectHub));
+                        instanceOfNode = new InstanceOfNode(hub, resolvedType, object, Collections.singletonList(subTypeHub), new RiResolvedType[] {uniqueSubtype}, false, false);
+                    } else {
+                        RiTypeProfile typeProfile = method.typeProfile(bci());
+                        if (typeProfile != null && typeProfile.types != null && typeProfile.types.length > 0) {
+                            ArrayList<ValueNode> hintInstructions = new ArrayList<>(typeProfile.types.length);
+                            RiResolvedType[] hints = new RiResolvedType[typeProfile.types.length];
+                            int hintCount = 0;
+
+                            for (RiResolvedType hint : typeProfile.types) {
+//                                TTY.println("profiled type: " + hint);
+                                if (hint.isSubtypeOf(resolvedType)) {
+                                    hintInstructions.add(appendConstant(hint.getEncoding(RiType.Representation.ObjectHub)));
+                                    hints[hintCount++] = hint;
+                                }
+                            }
+                            instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, hintInstructions, Arrays.copyOf(hints, hintCount), false, false);
+                        } else {
+                            instanceOfNode = new InstanceOfNode(hub, (RiResolvedType) type, object, false);
+                        }
+                    }
+                }
+            }
+            frameState.ipush(append(MaterializeNode.create(currentGraph.unique(instanceOfNode), currentGraph)));
         } else {
             PlaceholderNode trueSucc = currentGraph.add(new PlaceholderNode());
             DeoptimizeNode deopt = currentGraph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile));
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/CheckCastNode.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/CheckCastNode.java	Fri Feb 03 10:17:33 2012 +0100
@@ -22,8 +22,11 @@
  */
 package com.oracle.max.graal.nodes.java;
 
+import java.util.*;
+
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.graph.*;
 import com.oracle.max.graal.nodes.*;
 import com.oracle.max.graal.nodes.extended.*;
 import com.oracle.max.graal.nodes.spi.*;
@@ -32,10 +35,14 @@
 /**
  * The {@code CheckCastNode} represents a {@link Bytecodes#CHECKCAST}.
  */
-public final class CheckCastNode extends TypeCheckNode implements Canonicalizable, LIRLowerable {
+public final class CheckCastNode extends TypeCheckNode implements Canonicalizable, LIRLowerable, Node.IterableNodeType {
 
     @Input protected final AnchorNode anchor;
 
+    public AnchorNode anchor() {
+        return anchor;
+    }
+
     /**
      * Creates a new CheckCast instruction.
      *
@@ -44,7 +51,12 @@
      * @param object the instruction producing the object
      */
     public CheckCastNode(AnchorNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object) {
-        super(targetClassInstruction, targetClass, object, targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass));
+        this(anchor, targetClassInstruction, targetClass, object, null, EMPTY_HINTS, false);
+    }
+
+    public CheckCastNode(AnchorNode anchor, ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, List<? extends ValueNode> hintInstructions, RiResolvedType[] hints, boolean hintsExact) {
+        super(targetClassInstruction, targetClass, object, hintInstructions, hints, hintsExact, targetClass == null ? StampFactory.forKind(CiKind.Object) : StampFactory.declared(targetClass));
+        assert targetClass != null;
         this.anchor = anchor;
     }
 
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/InstanceOfNode.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/InstanceOfNode.java	Fri Feb 03 10:17:33 2012 +0100
@@ -22,6 +22,9 @@
  */
 package com.oracle.max.graal.nodes.java;
 
+import java.lang.reflect.*;
+import java.util.*;
+
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.graal.nodes.*;
@@ -48,7 +51,11 @@
      * @param object the instruction producing the object input to this instruction
      */
     public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, boolean negated) {
-        super(targetClassInstruction, targetClass, object, StampFactory.illegal());
+        this(targetClassInstruction, targetClass, object, null, EMPTY_HINTS, false, negated);
+    }
+
+    public InstanceOfNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, List<? extends ValueNode> hintInstructions, RiResolvedType[] hints, boolean hintsExact, boolean negated) {
+        super(targetClassInstruction, targetClass, object, hintInstructions, hints, hintsExact, StampFactory.illegal());
         this.negated = negated;
         assert targetClass != null;
     }
@@ -59,8 +66,23 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (object().exactType() != null) {
-            boolean result = object().exactType().isSubtypeOf(targetClass());
+        RiResolvedType exact = object().exactType();
+
+        if (exact == null) {
+            if (object().declaredType() != null) {
+                if (Modifier.isFinal(object().declaredType().accessFlags()) || object().declaredType().isArrayClass()) {
+                    exact = object().declaredType();
+                } else if (tool.assumptions() != null) {
+                    exact = object().declaredType().uniqueConcreteSubtype();
+                    if (exact != null) {
+                        tool.assumptions().recordConcreteSubtype(object().declaredType(), exact);
+                    }
+                }
+            }
+        }
+
+        if (exact != null) {
+            boolean result = exact.isSubtypeOf(targetClass());
             if (result != negated) {
                 // The instanceof check reduces to a null check.
                 return graph().unique(new NullCheckNode(object(), false));
@@ -78,11 +100,17 @@
                 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(), hintInstructions(), hints(), true, negated));
+            }
+        }
         return this;
     }
 
     @Override
     public BooleanNode negate() {
-        return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), !negated));
+        return graph().unique(new InstanceOfNode(targetClassInstruction(), targetClass(), object(), hintInstructions(), hints(), hintsExact(), !negated));
     }
 }
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/TypeCheckNode.java	Fri Feb 03 10:08:57 2012 +0100
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/TypeCheckNode.java	Fri Feb 03 10:17:33 2012 +0100
@@ -22,7 +22,10 @@
  */
 package com.oracle.max.graal.nodes.java;
 
+import java.util.*;
+
 import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.graph.*;
 import com.oracle.max.graal.nodes.*;
 import com.oracle.max.graal.nodes.type.*;
 
@@ -31,9 +34,13 @@
  */
 public abstract class TypeCheckNode extends BooleanNode {
 
+    protected static final RiResolvedType[] EMPTY_HINTS = new RiResolvedType[0];
     @Input private ValueNode object;
     @Input private ValueNode targetClassInstruction;
+    @Input private final NodeInputList<ValueNode> hintInstructions;
     @Data private final RiResolvedType targetClass;
+    @Data private final RiResolvedType[] hints;
+    @Data private final boolean hintsExact;
 
     /**
      * Creates a new TypeCheckNode.
@@ -42,11 +49,14 @@
      * @param object the node which produces the object
      * @param kind the result type of this node
      */
-    public TypeCheckNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, Stamp stamp) {
+    public TypeCheckNode(ValueNode targetClassInstruction, RiResolvedType targetClass, ValueNode object, List<? extends ValueNode> hintInstructions, RiResolvedType[] hints, boolean hintsExact, Stamp stamp) {
         super(stamp);
         this.targetClassInstruction = targetClassInstruction;
         this.targetClass = targetClass;
         this.object = object;
+        this.hintInstructions = new NodeInputList<>(this, hintInstructions);
+        this.hints = hints;
+        this.hintsExact = hintsExact;
     }
 
     public ValueNode object() {
@@ -64,4 +74,16 @@
     public RiResolvedType targetClass() {
         return targetClass;
     }
+
+    public NodeInputList<ValueNode> hintInstructions() {
+        return hintInstructions;
+    }
+
+    public RiResolvedType[] hints() {
+        return hints;
+    }
+
+    public boolean hintsExact() {
+        return hintsExact;
+    }
 }