changeset 4452:b225da954a32

inlining of multiple trival methods at one call site works
author Christian Haeubl <christian.haeubl@oracle.com>
date Fri, 27 Jan 2012 18:16:32 -0800
parents defa1b705f14
children c0430421d43d
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/gen/LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ObjectClassNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TypeSwitchNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/LIRGeneratorTool.java
diffstat 13 files changed, 133 insertions(+), 147 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.cri/src/com/oracle/max/cri/xir/RiXirGenerator.java	Fri Jan 27 18:16:32 2012 -0800
@@ -102,12 +102,12 @@
      * an object is identical to a given hub constant. In pseudo code:
      * <pre>
      *     if (object.getHub() != hub) {
-     *         uncommonTrap();
+     *       jump(falseSuccessor)
      *     }
      * </pre>
      * This snippet should only be used when the object is guaranteed not to be null.
      */
-    XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type);
+    XirSnippet genTypeBranch(XirSite site, XirArgument thisHub, XirArgument otherHub, RiType type);
 
     /**
      * Initializes the XIR generator for the given XIR assembler.
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jan 27 18:16:32 2012 -0800
@@ -689,9 +689,7 @@
 
     @Override
     public void emitGuardCheck(BooleanNode comp) {
-        if (comp instanceof IsTypeNode) {
-            emitTypeGuard((IsTypeNode) comp);
-        } else if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) {
+        if (comp instanceof NullCheckNode && !((NullCheckNode) comp).expectedNull) {
             emitNullCheckGuard((NullCheckNode) comp);
         } else if (comp instanceof ConstantNode && comp.asConstant().asBoolean()) {
             // True constant, nothing to emit.
@@ -711,14 +709,6 @@
         append(StandardOpcode.NULL_CHECK.create(value, info));
     }
 
-    private void emitTypeGuard(IsTypeNode node) {
-        load(operand(node.object()));
-        LIRDebugInfo info = state();
-        XirArgument clazz = toXirArgument(node.type().getEncoding(Representation.ObjectHub));
-        XirSnippet typeCheck = xir.genTypeCheck(site(node), toXirArgument(node.object()), clazz, node.type());
-        emitXir(typeCheck, node, info, method, false);
-    }
-
     public void emitBranch(BooleanNode node, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
         if (node instanceof NullCheckNode) {
             emitNullCheckBranch((NullCheckNode) node, trueSuccessor, falseSuccessor, info);
@@ -728,6 +718,8 @@
             emitInstanceOfBranch((InstanceOfNode) node, trueSuccessor, falseSuccessor, info);
         } else if (node instanceof ConstantNode) {
             emitConstantBranch(((ConstantNode) node).asConstant().asBoolean(), trueSuccessor, falseSuccessor, info);
+        } else if (node instanceof IsTypeNode) {
+            emitTypeBranch((IsTypeNode) node, trueSuccessor, falseSuccessor, info);
         } else {
             throw Util.unimplemented(node.toString());
         }
@@ -757,7 +749,6 @@
         instr.setFalseSuccessor(x.negated ? trueSuccessor : falseSuccessor);
     }
 
-
     public void emitConstantBranch(boolean value, LabelRef trueSuccessorBlock, LabelRef falseSuccessorBlock, LIRDebugInfo info) {
         LabelRef block = value ? trueSuccessorBlock : falseSuccessorBlock;
         if (block != null) {
@@ -765,6 +756,19 @@
         }
     }
 
+    public void emitTypeBranch(IsTypeNode x, LabelRef trueSuccessor, LabelRef falseSuccessor, LIRDebugInfo info) {
+        XirArgument thisClass = toXirArgument(x.objectClass());
+        XirArgument otherClass = toXirArgument(x.type().getEncoding(Representation.ObjectHub));
+        XirSnippet snippet = xir.genTypeBranch(site(x), thisClass, otherClass, x.type());
+        emitXir(snippet, x, info, null, method, false);
+
+        LIRXirInstruction instr = (LIRXirInstruction) currentBlock.lir().get(currentBlock.lir().size() - 1);
+        instr.setFalseSuccessor(falseSuccessor);
+        if (trueSuccessor != null) {
+            emitJump(trueSuccessor, null);
+        }
+    }
+
     @Override
     public void emitConditional(ConditionalNode conditional) {
         CiValue tVal = operand(conditional.trueValue());
@@ -1033,21 +1037,6 @@
     }
 
     @Override
-    public void emitTypeSwitch(TypeSwitchNode x) {
-        Variable tag = load(operand(x.value()));
-        LIRDebugInfo info = state();
-
-        int len = x.typesLength();
-        for (int i = 0; i < len; i++) {
-            CiConstant type = x.typeAt(i).getEncoding(Representation.ObjectHub);
-            emitBranch(tag, type, Condition.EQ, false, getLIRBlock(x.blockSuccessor(i)), null);
-        }
-
-        LabelRef stubEntry = createDeoptStub(DeoptAction.InvalidateReprofile, info, x);
-        emitJump(stubEntry, info);
-    }
-
-    @Override
     public void emitTableSwitch(TableSwitchNode x) {
         Variable value = load(operand(x.value()));
         // TODO: tune the defaults for the controls used to determine what kind of translation to use
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Jan 27 18:16:32 2012 -0800
@@ -315,7 +315,7 @@
                 assert ((NullCheckNode) usage).object() == node;
                 return null;
             } else if (usage instanceof IsTypeNode) {
-                assert ((IsTypeNode) usage).object() == node;
+                assert ((IsTypeNode) usage).objectClass() == node;
                 return null;
             } else if (usage instanceof AccessMonitorNode) {
                 assert ((AccessMonitorNode) usage).object() == node;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/InliningUtil.java	Fri Jan 27 18:16:32 2012 -0800
@@ -154,8 +154,10 @@
 
         @Override
         public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
+            // receiver null check must be before the type check
             InliningUtil.receiverNullCheck(invoke);
-            IsTypeNode isTypeNode = graph.unique(new IsTypeNode(invoke.callTarget().receiver(), type));
+            ObjectClassNode objectClass = new ObjectClassNode(invoke.callTarget().receiver());
+            IsTypeNode isTypeNode = graph.unique(new IsTypeNode(objectClass, type));
             FixedGuardNode guard = graph.add(new FixedGuardNode(isTypeNode));
             assert invoke.predecessor() != null;
             graph.addBeforeFixed(invoke.node(), guard);
@@ -204,7 +206,9 @@
         public void inline(StructuredGraph graph, GraalRuntime runtime, InliningCallback callback) {
             MethodCallTargetNode callTargetNode = invoke.callTarget();
             int numberOfMethods = concretes.size();
+            boolean hasReturnValue = callTargetNode.kind() != CiKind.Void;
 
+            // receiver null check must be the first node
             InliningUtil.receiverNullCheck(invoke);
 
             // save node after invoke so that invoke can be deleted safely
@@ -214,11 +218,13 @@
             // setup a merge node and a phi node for the result
             MergeNode merge = null;
             PhiNode returnValuePhi = null;
+            Node returnValue = null;
             if (numberOfMethods > 1) {
                 merge = graph.add(new MergeNode());
                 merge.setNext(continuation);
-                if (callTargetNode.kind() != CiKind.Void) {
+                if (hasReturnValue) {
                     returnValuePhi = graph.unique(new PhiNode(callTargetNode.kind(), merge, PhiType.Value));
+                    returnValue = returnValuePhi;
                 }
             }
 
@@ -237,29 +243,31 @@
                     }
                 } else {
                     duplicatedInvoke.setNext(continuation);
+                    if (hasReturnValue) {
+                        returnValue = (Node) duplicatedInvoke;
+                    }
                 }
             }
 
-            // match successor method and types
-            BeginNode[] switchSuccessors = new BeginNode[types.length + 1];
-            for (int i = 0; i < typesToConcretes.length; i++) {
-                switchSuccessors[i] = successorMethods[typesToConcretes[i]];
+            // create a cascade of ifs with the type checks
+            ObjectClassNode objectClassNode = graph.add(new ObjectClassNode(invoke.callTarget().receiver()));
+
+            int lastIndex = types.length - 1;
+            BeginNode tsux = successorMethods[typesToConcretes[lastIndex]];
+            IsTypeNode isTypeNode = graph.add(new IsTypeNode(objectClassNode, types[lastIndex]));
+            FixedGuardNode guardNode = graph.add(new FixedGuardNode(isTypeNode));
+            guardNode.setNext(tsux);
+
+            FixedNode nextNode = guardNode;
+            for (int i = lastIndex - 1; i >= 0; i--) {
+                tsux = successorMethods[typesToConcretes[i]];
+                isTypeNode = graph.add(new IsTypeNode(objectClassNode, types[i]));
+                nextNode = graph.add(new IfNode(isTypeNode, tsux, nextNode, probabilities[i]));
             }
 
-            // set default successor to deoptimization
-            DeoptimizeNode deoptNode = graph.add(new DeoptimizeNode(DeoptAction.InvalidateRecompile));
-            switchSuccessors[types.length] = BeginNode.begin(deoptNode);
-
-            // replace usage of original invocation with phi(returnValues)
-            if (returnValuePhi != null) {
-                for (Node usage: invoke.node().usages().snapshot()) {
-                    usage.replaceFirstInput(invoke.node(), returnValuePhi);
-                }
-            }
-
-            // replace the original invocation with the TypeSwitch
-            TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(callTargetNode.receiver(), switchSuccessors, types, probabilities));
-            invoke.node().replaceAndDelete(typeSwitch);
+            // replace the original invocation with a cascade of if nodes and replace the usages of invoke with the return value (phi or duplicatedInvoke)
+            invoke.node().replaceAtUsages(returnValue);
+            invoke.node().replaceAndDelete(nextNode);
             GraphUtil.killCFG(invoke.node());
 
             // do the actual inlining for every invocation
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotMethodData.java	Fri Jan 27 18:16:32 2012 -0800
@@ -251,6 +251,7 @@
             super(tag, staticSize);
         }
 
+        @SuppressWarnings("unused")
         public boolean getNullSeen(HotSpotMethodData data, int position) {
             return (getFlags(data, position) & BIT_DATA_NULL_SEEN_FLAG) != 0;
         }
@@ -302,6 +303,11 @@
         public int getExecutionCount(HotSpotMethodData data, int position) {
             return data.readUnsignedIntAsSignedInt(position, TAKEN_COUNT_OFFSET);
         }
+
+        @SuppressWarnings("unused")
+        public int getTakenDisplacement(HotSpotMethodData data, int position) {
+            return data.readInt(position, TAKEN_DISPLACEMENT_OFFSET);
+        }
     }
 
     private static class AbstractTypeData extends CounterData {
@@ -538,6 +544,11 @@
         private static int getCountOffset(int index) {
             return MULTI_BRANCH_DATA_FIRST_COUNT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
         }
+
+        @SuppressWarnings("unused")
+        private static int getDisplacementOffset(int index) {
+            return MULTI_BRANCH_DATA_FIRST_DISPLACEMENT_OFFSET + index * MULTI_BRANCH_DATA_ROW_SIZE;
+        }
     }
 
     private static class ArgInfoData extends ArrayData {
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotRuntime.java	Fri Jan 27 18:16:32 2012 -0800
@@ -313,6 +313,13 @@
         } else if (n instanceof ArrayHeaderSizeNode) {
             ArrayHeaderSizeNode arrayHeaderSize = (ArrayHeaderSizeNode) n;
             graph.replaceFloating(arrayHeaderSize, ConstantNode.forLong(config.getArrayOffset(arrayHeaderSize.elementKind()), n.graph()));
+        } else if (n instanceof ObjectClassNode) {
+            ObjectClassNode objectClassNode = (ObjectClassNode) n;
+            LocationNode location = LocationNode.create(LocationNode.FINAL_LOCATION, CiKind.Object, config.hubOffset, graph);
+            FloatingReadNode memoryRead = graph.add(new FloatingReadNode(CiKind.Object, objectClassNode.object(), null, location));
+            // TODO (ch) this fails because ObjectClass is only used as an input value
+            //memoryRead.setGuard((GuardNode) tool.createGuard(graph.unique(new NullCheckNode(objectClassNode.object(), false))));
+            graph.replaceFloating(objectClassNode, memoryRead);
         }
     }
 
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/ri/HotSpotXirGenerator.java	Fri Jan 27 18:16:32 2012 -0800
@@ -1107,32 +1107,21 @@
        @Override
        protected XirTemplate create(CiXirAssembler asm, long flags) {
            asm.restart();
-           XirParameter object = asm.createInputParameter("object", CiKind.Object);
+           XirParameter objHub = asm.createInputParameter("objectHub", CiKind.Object);
            XirOperand hub = asm.createConstantInputParameter("hub", CiKind.Object);
+           XirLabel falseSucc = asm.createInlineLabel(XirLabel.FalseSuccessor);
 
-           XirOperand objHub = asm.createTemp("objHub", CiKind.Object);
            XirOperand checkHub = asm.createTemp("checkHub", CiKind.Object);
 
-           XirLabel slowPath = asm.createOutOfLineLabel("deopt");
-
            if (is(NULL_CHECK, flags)) {
                asm.mark(MARK_IMPLICIT_NULL);
            }
 
-           asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
            asm.mov(checkHub, hub);
            // if we get an exact match: continue
-           asm.jneq(slowPath, objHub, checkHub);
+           asm.jneq(falseSucc, objHub, checkHub);
 
-           // -- out of line -------------------------------------------------------
-           asm.bindOutOfLine(slowPath);
-           XirOperand scratch = asm.createRegisterTemp("scratch", target.wordKind, AMD64.r10);
-           asm.mov(scratch, wordConst(asm, 2));
-
-           asm.callRuntime(CiRuntimeCall.Deoptimize, null);
-           asm.shouldNotReachHere();
-
-           return asm.finishTemplate(object, "typeCheck");
+           return asm.finishTemplate(objHub, "typeCheck");
        }
     };
 
@@ -1300,9 +1289,9 @@
     }
 
     @Override
-    public XirSnippet genTypeCheck(XirSite site, XirArgument object, XirArgument hub, RiType type) {
+    public XirSnippet genTypeBranch(XirSite site, XirArgument thisHub, XirArgument otherHub, RiType type) {
         assert type instanceof RiResolvedType;
-        return new XirSnippet(typeCheckTemplates.get(site), object, hub);
+        return new XirSnippet(typeCheckTemplates.get(site), thisHub, otherHub);
     }
 
     @Override
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/IfNode.java	Fri Jan 27 18:16:32 2012 -0800
@@ -44,8 +44,8 @@
         return compare;
     }
 
-    public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double probability) {
-        super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {probability, 1 - probability});
+    public IfNode(BooleanNode condition, FixedNode trueSuccessor, FixedNode falseSuccessor, double takenProbability) {
+        super(StampFactory.illegal(), new BeginNode[] {BeginNode.begin(trueSuccessor), BeginNode.begin(falseSuccessor)}, new double[] {takenProbability, 1 - takenProbability});
         this.compare = condition;
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/ObjectClassNode.java	Fri Jan 27 18:16:32 2012 -0800
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.nodes.extended;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.graal.cri.*;
+import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.calc.*;
+import com.oracle.max.graal.nodes.spi.*;
+import com.oracle.max.graal.nodes.type.*;
+
+public final class ObjectClassNode extends FloatingNode implements Lowerable {
+    @Input private ValueNode object;
+
+    public ValueNode object() {
+        return object;
+    }
+
+    public ObjectClassNode(ValueNode object) {
+        super(StampFactory.forKind(CiKind.Object));
+        this.object = object;
+    }
+
+    @Override
+    public void lower(CiLoweringTool tool) {
+        tool.getRuntime().lower(this, tool);
+    }
+}
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/extended/TypeSwitchNode.java	Fri Jan 27 12:15:12 2012 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +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.max.graal.nodes.extended;
-
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.graal.nodes.*;
-import com.oracle.max.graal.nodes.spi.*;
-
-/**
- * The {@code TypeSwitchNode} is a switch node that dispatches to a successor based on a given type.
- */
-public final class TypeSwitchNode extends SwitchNode implements LIRLowerable {
-
-    @Data private final RiResolvedType[] types;
-
-    /**
-     * Constructs a new TypeSwitchNode instruction.
-     * @param object the instruction producing the value which type should be tested
-     * @param successors the list of successors (default successor is last entry)
-     * @param types the list of types, same order as successors but no value for default successor
-     * @param probability the list of probabilities, same order as successors
-     */
-    public TypeSwitchNode(ValueNode object, BeginNode[] successors, RiResolvedType[] types, double[] probability) {
-        super(object, successors, probability);
-        assert object.exactType() == null : "emitting useless guard";
-        this.types = types;
-    }
-
-    /**
-     * Gets the type at the specified index.
-     * @param i the index
-     * @return the type at that index
-     */
-    public RiResolvedType typeAt(int i) {
-        return types[i];
-    }
-
-    public int typesLength() {
-        return types.length;
-    }
-
-    @Override
-    public void generate(LIRGeneratorTool gen) {
-        gen.emitTypeSwitch(this);
-    }
-}
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/java/IsTypeNode.java	Fri Jan 27 18:16:32 2012 -0800
@@ -27,30 +27,30 @@
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.extended.*;
 import com.oracle.max.graal.nodes.spi.*;
 import com.oracle.max.graal.nodes.type.*;
 
 public final class IsTypeNode extends BooleanNode implements Canonicalizable, LIRLowerable {
 
-    @Input private ValueNode object;
+    @Input private ValueNode objectClass;
+    @Data private final RiResolvedType type;
 
-    public ValueNode object() {
-        return object;
+    public ValueNode objectClass() {
+        return objectClass;
     }
 
-    private final RiResolvedType type;
-
     /**
      * Constructs a new IsTypeNode.
      *
      * @param object the instruction producing the object to check against the given type
      * @param type the type for this check
      */
-    public IsTypeNode(ValueNode object, RiResolvedType type) {
+    public IsTypeNode(ValueNode objectClass, RiResolvedType type) {
         super(StampFactory.illegal());
-        assert object == null || object.kind() == CiKind.Object;
+        assert objectClass == null || objectClass.kind() == CiKind.Object;
         this.type = type;
-        this.object = object;
+        this.objectClass = objectClass;
     }
 
     public RiResolvedType type() {
@@ -71,8 +71,9 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (object().exactType() != null) {
-            return ConstantNode.forBoolean(object().exactType() == type(), graph());
+        RiResolvedType exactType = objectClass() instanceof ObjectClassNode ? ((ObjectClassNode) objectClass()).object().exactType() : null;
+        if (exactType != null) {
+            return ConstantNode.forBoolean(exactType == type(), graph());
         }
         // constants return the correct exactType, so they are handled by the code above
         return this;
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/EscapeOp.java	Fri Jan 27 18:16:32 2012 -0800
@@ -41,7 +41,7 @@
             assert ((NullCheckNode) usage).object() == node;
             return false;
         } else if (usage instanceof IsTypeNode) {
-            assert ((IsTypeNode) usage).object() == node;
+            assert ((IsTypeNode) usage).objectClass() == node;
             return false;
         } else if (usage instanceof FrameState) {
             assert ((FrameState) usage).inputs().contains(node);
--- a/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/LIRGeneratorTool.java	Fri Jan 27 12:15:12 2012 -0800
+++ b/graal/com.oracle.max.graal.nodes/src/com/oracle/max/graal/nodes/spi/LIRGeneratorTool.java	Fri Jan 27 18:16:32 2012 -0800
@@ -88,7 +88,6 @@
 
     public abstract void emitLookupSwitch(LookupSwitchNode i);
     public abstract void emitTableSwitch(TableSwitchNode i);
-    public abstract void emitTypeSwitch(TypeSwitchNode x);
 
     public abstract void emitInvoke(Invoke i);
     public abstract void emitRuntimeCall(RuntimeCallNode i);