changeset 11752:7e7edb86fb43

Refactor the handling of unsafe casts to distinguish between word-object-conversions, PiNode-like type information, and real unsafe casts.
author Christian Wimmer <christian.wimmer@oracle.com>
date Mon, 23 Sep 2013 14:36:00 -0700
parents 29de278b7c1b
children 095325ccbf9a
files graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/TypeCastNode.java graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java
diffstat 18 files changed, 239 insertions(+), 189 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/AheadOfTimeCompilationTest.java	Mon Sep 23 14:36:00 2013 -0700
@@ -175,7 +175,7 @@
         StructuredGraph result = compile("getBoxedBoolean", true);
 
         assertEquals(2, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(1, result.getNodes(UnsafeCastNode.class).count());
+        assertEquals(1, result.getNodes(PiNode.class).count());
         assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
         ConstantNode constant = result.getNodes().filter(ConstantNode.class).first();
         assertEquals(Kind.Long, constant.kind());
@@ -186,7 +186,7 @@
     public void testBoxedBoolean() {
         StructuredGraph result = compile("getBoxedBoolean", false);
         assertEquals(0, result.getNodes(FloatingReadNode.class).count());
-        assertEquals(0, result.getNodes(UnsafeCastNode.class).count());
+        assertEquals(0, result.getNodes(PiNode.class).count());
         assertEquals(1, result.getNodes().filter(ConstantNode.class).count());
         ConstantNode constant = result.getNodes().filter(ConstantNode.class).first();
         assertEquals(Kind.Object, constant.kind());
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/CheckCastDynamicSnippets.java	Mon Sep 23 14:36:00 2013 -0700
@@ -26,8 +26,8 @@
 import static com.oracle.graal.api.meta.DeoptimizationReason.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
 import static com.oracle.graal.hotspot.replacements.TypeCheckSnippetUtils.*;
+import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
@@ -59,7 +59,7 @@
             }
         }
         BeginNode anchorNode = BeginNode.anchor();
-        return unsafeCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode);
+        return piCast(verifyOop(object), StampFactory.forNodeIntrinsic(), anchorNode);
     }
 
     public static class Templates extends AbstractTemplates {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ClassSubstitutions.java	Mon Sep 23 14:36:00 2013 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 
 import java.lang.reflect.*;
 
@@ -96,7 +96,7 @@
                     if (superKlass.equal(0)) {
                         return null;
                     } else {
-                        return unsafeCast(superKlass.readObject(classMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
+                        return piCast(superKlass.readObject(classMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
                     }
                 }
             }
@@ -110,7 +110,7 @@
         Word klass = loadWordFromObject(thisObj, klassOffset());
         if (klass.notEqual(0)) {
             if ((readLayoutHelper(klass) & arrayKlassLayoutHelperIdentifier()) != 0) {
-                return unsafeCast(klass.readObject(arrayKlassComponentMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
+                return piCast(klass.readObject(arrayKlassComponentMirrorOffset(), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
             }
         }
         return null;
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/LoadExceptionObjectSnippets.java	Mon Sep 23 14:36:00 2013 -0700
@@ -24,7 +24,7 @@
 
 import static com.oracle.graal.hotspot.meta.HotSpotRuntime.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 
 import com.oracle.graal.api.code.*;
@@ -57,7 +57,7 @@
         Object exception = readExceptionOop(thread);
         writeExceptionOop(thread, null);
         writeExceptionPc(thread, Word.zero());
-        return unsafeCast(exception, StampFactory.forNodeIntrinsic());
+        return piCast(exception, StampFactory.forNodeIntrinsic());
     }
 
     public static class Templates extends AbstractTemplates {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Mon Sep 23 14:36:00 2013 -0700
@@ -25,9 +25,9 @@
 import static com.oracle.graal.api.code.UnsignedMath.*;
 import static com.oracle.graal.api.meta.LocationIdentity.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
+import static com.oracle.graal.nodes.PiArrayNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-import static com.oracle.graal.nodes.extended.UnsafeArrayCastNode.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
 import static com.oracle.graal.phases.GraalOptions.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*;
@@ -35,6 +35,8 @@
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.Node.ConstantNodeParameter;
+import com.oracle.graal.graph.Node.NodeIntrinsic;
 import com.oracle.graal.hotspot.meta.*;
 import com.oracle.graal.hotspot.nodes.*;
 import com.oracle.graal.nodes.*;
@@ -87,8 +89,7 @@
             new_stub.inc();
             result = NewInstanceStubCall.call(hub);
         }
-        BeginNode anchorNode = BeginNode.anchor();
-        return unsafeCast(verifyOop(result), StampFactory.forNodeIntrinsic(), anchorNode);
+        return piCast(verifyOop(result), StampFactory.forNodeIntrinsic());
     }
 
     /**
@@ -121,8 +122,7 @@
             newarray_stub.inc();
             result = NewArrayStubCall.call(hub, length);
         }
-        BeginNode anchorNode = BeginNode.anchor();
-        return unsafeArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic(), anchorNode);
+        return piArrayCast(verifyOop(result), length, StampFactory.forNodeIntrinsic());
     }
 
     public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class);
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectSubstitutions.java	Mon Sep 23 14:36:00 2013 -0700
@@ -23,7 +23,7 @@
 package com.oracle.graal.hotspot.replacements;
 
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-import static com.oracle.graal.nodes.extended.UnsafeCastNode.*;
+import static com.oracle.graal.nodes.PiNode.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.api.replacements.*;
@@ -41,7 +41,7 @@
     @MethodSubstitution(isStatic = false, forced = true)
     public static Class<?> getClass(final Object thisObj) {
         Word hub = loadHub(thisObj);
-        return unsafeCast(hub.readObject(Word.signed(classMirrorOffset()), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
+        return piCast(hub.readObject(Word.signed(classMirrorOffset()), LocationIdentity.FINAL_LOCATION), Class.class, true, true);
     }
 
     @MethodSubstitution(isStatic = false)
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/GuardingPiNode.java	Mon Sep 23 14:36:00 2013 -0700
@@ -82,7 +82,7 @@
         }
         GuardingNode guard = tool.createGuard(condition, reason, action, negated);
         ValueAnchorNode anchor = graph().add(new ValueAnchorNode((ValueNode) guard));
-        PiNode pi = graph().unique(new PiNode(object, stamp(), guard));
+        PiNode pi = graph().unique(new PiNode(object, stamp(), (ValueNode) guard));
         replaceAtUsages(pi);
         graph().replaceFixedWithFixed(this, anchor);
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiArrayNode.java	Mon Sep 23 14:36:00 2013 -0700
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes;
+
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * The {@code UnsafeCastNode} produces the same value as its input, but with a different type.
+ */
+public final class PiArrayNode extends PiNode implements ArrayLengthProvider {
+
+    @Input private ValueNode length;
+
+    public ValueNode length() {
+        return length;
+    }
+
+    public PiArrayNode(ValueNode object, ValueNode length, Stamp stamp) {
+        super(object, stamp);
+        this.length = length;
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (!(object() instanceof ArrayLengthProvider) || length() != ((ArrayLengthProvider) object()).length()) {
+            return this;
+        }
+        return super.canonical(tool);
+    }
+
+    @NodeIntrinsic
+    public static native <T> T piArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
+}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Mon Sep 23 14:36:00 2013 -0700
@@ -49,13 +49,21 @@
         this.object = object;
     }
 
-    public PiNode(ValueNode object, Stamp stamp, GuardingNode anchor) {
-        super(stamp, anchor);
+    public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
+        super(stamp, (GuardingNode) anchor);
         this.object = object;
     }
 
+    public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
+        this(object, StampFactory.object(toType, exactType, nonNull || ObjectStamp.isObjectNonNull(object.stamp())));
+    }
+
     @Override
     public void generate(LIRGeneratorTool generator) {
+        assert kind() == Kind.Object && object.kind() == Kind.Object;
+        assert ObjectStamp.typeOrNull(object) == null || ObjectStamp.typeOrNull(this).isInterface() || ObjectStamp.typeOrNull(object).isInterface() ||
+                        ObjectStamp.typeOrNull(object).isAssignableFrom(ObjectStamp.typeOrNull(this));
+
         if (object.kind() != Kind.Void && object.kind() != Kind.Illegal) {
             generator.setResult(this, generator.operand(object));
         }
@@ -63,6 +71,9 @@
 
     @Override
     public boolean inferStamp() {
+        if (stamp() == StampFactory.forNodeIntrinsic()) {
+            return false;
+        }
         return updateStamp(stamp().join(object().stamp()));
     }
 
@@ -70,14 +81,7 @@
     public void virtualize(VirtualizerTool tool) {
         State state = tool.getObjectState(object);
         if (state != null && state.getState() == EscapeState.Virtual) {
-            ResolvedJavaType virtualObjectType = state.getVirtualObject().type();
-            if (this.kind() == Kind.Object) {
-                ObjectStamp myStamp = ((ObjectStamp) this.stamp());
-                ResolvedJavaType myType = myStamp.type();
-                if (!myType.isAssignableFrom(virtualObjectType)) {
-                    return;
-                }
-            }
+            assert ObjectStamp.typeOrNull(this).isAssignableFrom(state.getVirtualObject().type());
             tool.replaceWithVirtual(state.getVirtualObject());
         }
     }
@@ -95,4 +99,16 @@
     public ValueNode getOriginalValue() {
         return object;
     }
+
+    @NodeIntrinsic
+    public static native <T> T piCast(Object object, @ConstantNodeParameter Stamp stamp);
+
+    @NodeIntrinsic
+    public static native <T> T piCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
+
+    @SuppressWarnings("unused")
+    @NodeIntrinsic
+    public static <T> T piCast(Object object, @ConstantNodeParameter Class<T> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) {
+        return toType.cast(object);
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeArrayCastNode.java	Sun Sep 22 02:24:13 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.extended;
-
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-
-/**
- * The {@code UnsafeCastNode} produces the same value as its input, but with a different type.
- */
-public final class UnsafeArrayCastNode extends UnsafeCastNode implements ArrayLengthProvider {
-
-    @Input private ValueNode length;
-
-    public ValueNode length() {
-        return length;
-    }
-
-    public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp) {
-        super(object, stamp);
-        this.length = length;
-    }
-
-    public UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, GuardingNode anchor) {
-        super(object, stamp, anchor);
-        this.length = length;
-    }
-
-    private UnsafeArrayCastNode(ValueNode object, ValueNode length, Stamp stamp, ValueNode anchor) {
-        this(object, length, stamp, (GuardingNode) anchor);
-    }
-
-    @Override
-    public ValueNode canonical(CanonicalizerTool tool) {
-        if (!(object() instanceof ArrayLengthProvider) || length() != ((ArrayLengthProvider) object()).length()) {
-            return this;
-        }
-        return super.canonical(tool);
-    }
-
-    @NodeIntrinsic
-    public static native <T> T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp);
-
-    @NodeIntrinsic
-    public static native <T> T unsafeArrayCast(Object object, int length, @ConstantNodeParameter Stamp stamp, Object anchor);
-}
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Mon Sep 23 14:36:00 2013 -0700
@@ -23,25 +23,29 @@
 package com.oracle.graal.nodes.extended;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
 /**
- * The {@code UnsafeCastNode} produces the same value as its input, but with a different type.
+ * The {@code UnsafeCastNode} produces the same value as its input, but with a different type. It
+ * allows unsafe casts "sideways" in the type hierarchy. It does not allow to "drop" type
+ * information, i.e., an unsafe cast is removed if the input object has a more precise or equal type
+ * than the type this nodes casts to.
  */
-public class UnsafeCastNode extends PiNode implements Canonicalizable, LIRLowerable {
+public class UnsafeCastNode extends FloatingGuardedNode implements LIRLowerable, GuardingNode, IterableNodeType, Canonicalizable, ValueProxy {
+
+    @Input private ValueNode object;
 
     public UnsafeCastNode(ValueNode object, Stamp stamp) {
-        super(object, stamp);
-    }
-
-    public UnsafeCastNode(ValueNode object, Stamp stamp, GuardingNode anchor) {
-        super(object, stamp, anchor);
+        super(stamp);
+        this.object = object;
     }
 
     public UnsafeCastNode(ValueNode object, Stamp stamp, ValueNode anchor) {
-        this(object, stamp, (GuardingNode) anchor);
+        super(stamp, (GuardingNode) anchor);
+        this.object = object;
     }
 
     public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
@@ -49,66 +53,44 @@
     }
 
     @Override
-    public boolean inferStamp() {
-        if (stamp() == StampFactory.forNodeIntrinsic()) {
-            return false;
-        }
-        if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            return updateStamp(((ObjectStamp) object().stamp()).castTo((ObjectStamp) stamp()));
-        }
-        return false;
+    public ValueNode getOriginalValue() {
+        return object;
     }
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
-        if (kind() != object().kind()) {
+        assert kind() == Kind.Object && object.kind() == Kind.Object;
+
+        ObjectStamp my = (ObjectStamp) stamp();
+        ObjectStamp other = (ObjectStamp) object.stamp();
+
+        if (my.type() == null || other.type() == null) {
+            return this;
+        }
+        if (my.isExactType() && !other.isExactType()) {
             return this;
         }
-
-        if (stamp() instanceof ObjectStamp && object().stamp() instanceof ObjectStamp) {
-            ObjectStamp my = (ObjectStamp) stamp();
-            ObjectStamp other = (ObjectStamp) object().stamp();
-
-            if (my.type() == null || other.type() == null) {
-                return this;
-            }
-            if (my.isExactType() && !other.isExactType()) {
-                return this;
-            }
-            if (my.nonNull() && !other.nonNull()) {
-                return this;
-            }
-            if (!my.type().isAssignableFrom(other.type())) {
-                return this;
-            }
+        if (my.nonNull() && !other.nonNull()) {
+            return this;
+        }
+        if (!my.type().isAssignableFrom(other.type())) {
+            return this;
         }
-        return object();
+        /*
+         * The unsafe cast does not add any new type information, so it can be removed. Note that
+         * this means that the unsafe cast cannot be used to "drop" type information (in which case
+         * it must not be canonicalized in any case).
+         */
+        return object;
     }
 
     @Override
     public void generate(LIRGeneratorTool generator) {
-        if (kind() != object().kind()) {
-            assert generator.target().arch.getSizeInBytes(kind()) == generator.target().arch.getSizeInBytes(object().kind()) : "unsafe cast cannot be used to change the size of a value";
-            AllocatableValue result = generator.newVariable(kind());
-            generator.emitMove(result, generator.operand(object()));
-            generator.setResult(this, result);
-        } else {
-            // The LIR only cares about the kind of an operand, not the actual type of an object. So
-            // we do not have to
-            // introduce a new operand when the kind is the same.
-            generator.setResult(this, generator.operand(object()));
-        }
-    }
-
-    @NodeIntrinsic
-    public static native <T> T unsafeCast(Object object, @ConstantNodeParameter Stamp stamp);
-
-    @NodeIntrinsic
-    public static native <T> T unsafeCast(Object object, @ConstantNodeParameter Stamp stamp, GuardingNode anchor);
-
-    @SuppressWarnings("unused")
-    @NodeIntrinsic
-    public static <T> T unsafeCast(Object object, @ConstantNodeParameter Class<T> toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull) {
-        return toType.cast(object);
+        assert kind() == Kind.Object && object.kind() == Kind.Object;
+        /*
+         * The LIR only cares about the kind of an operand, not the actual type of an object. So we
+         * do not have to introduce a new operand.
+         */
+        generator.setResult(this, generator.operand(object));
     }
 }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConditionalEliminationPhase.java	Mon Sep 23 14:36:00 2013 -0700
@@ -511,9 +511,9 @@
                     PiNode piNode;
                     if (isNull) {
                         ConstantNode nullObject = ConstantNode.forObject(null, metaAccessProvider, graph);
-                        piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.value, metaAccessProvider), replacementAnchor));
+                        piNode = graph.unique(new PiNode(nullObject, StampFactory.forConstant(nullObject.value, metaAccessProvider), replacementAnchor.asNode()));
                     } else {
-                        piNode = graph.unique(new PiNode(object, StampFactory.declared(type, nonNull), replacementAnchor));
+                        piNode = graph.unique(new PiNode(object, StampFactory.declared(type, nonNull), replacementAnchor.asNode()));
                     }
                     checkCast.replaceAtUsages(piNode);
                     if (anchor != null) {
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/PointerTest.java	Mon Sep 23 14:36:00 2013 -0700
@@ -36,6 +36,7 @@
 import com.oracle.graal.replacements.*;
 import com.oracle.graal.replacements.Snippet.*;
 import com.oracle.graal.word.*;
+import com.oracle.graal.word.nodes.*;
 
 /**
  * Tests for the {@link Pointer} read and write operations.
@@ -103,11 +104,13 @@
     }
 
     private void assertRead(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
-        ReadNode read = (ReadNode) graph.start().next();
+        WordCastNode cast = (WordCastNode) graph.start().next();
+
+        ReadNode read = (ReadNode) cast.next();
         Assert.assertEquals(kind.getStackKind(), read.kind());
 
-        UnsafeCastNode cast = (UnsafeCastNode) read.object();
-        Assert.assertEquals(graph.getLocal(0), cast.object());
+        Assert.assertEquals(cast, read.object());
+        Assert.assertEquals(graph.getLocal(0), cast.getInput());
         Assert.assertEquals(target.wordKind, cast.kind());
 
         IndexedLocationNode location = (IndexedLocationNode) read.location();
@@ -128,13 +131,15 @@
     }
 
     private void assertWrite(StructuredGraph graph, Kind kind, boolean indexConvert, LocationIdentity locationIdentity) {
-        WriteNode write = (WriteNode) graph.start().next();
+        WordCastNode cast = (WordCastNode) graph.start().next();
+
+        WriteNode write = (WriteNode) cast.next();
         Assert.assertEquals(graph.getLocal(2), write.value());
         Assert.assertEquals(Kind.Void, write.kind());
         Assert.assertEquals(FrameState.AFTER_BCI, write.stateAfter().bci);
 
-        UnsafeCastNode cast = (UnsafeCastNode) write.object();
-        Assert.assertEquals(graph.getLocal(0), cast.object());
+        Assert.assertEquals(cast, write.object());
+        Assert.assertEquals(graph.getLocal(0), cast.getInput());
         Assert.assertEquals(target.wordKind, cast.kind());
 
         IndexedLocationNode location = (IndexedLocationNode) write.location();
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/BoxingSnippets.java	Mon Sep 23 14:36:00 2013 -0700
@@ -79,49 +79,49 @@
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Boolean booleanValueOf(boolean value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Boolean.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Byte byteValueOf(byte value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Byte.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Character charValueOf(char value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Character.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Double doubleValueOf(double value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Double.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Float floatValueOf(float value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Float.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Integer intValueOf(int value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Integer.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Long longValueOf(long value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Long.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
     public static Short shortValueOf(short value) {
         valueOfCounter.inc();
-        return UnsafeCastNode.unsafeCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
+        return PiNode.piCast(Short.valueOf(value), StampFactory.forNodeIntrinsic());
     }
 
     @Snippet(inlining = BoxingSnippetInliningPolicy.class)
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/NodeClassSubstitutions.java	Mon Sep 23 14:36:00 2013 -0700
@@ -36,8 +36,8 @@
  * Substitutions for improving the performance of some critical methods in {@link NodeClass}
  * methods. These substitutions improve the performance by forcing the relevant methods to be
  * inlined (intrinsification being a special form of inlining) and removing a checked cast. The
- * latter cannot be done directly in Java code as {@link UnsafeCastNode} is not available to the
- * project containing {@link NodeClass}.
+ * latter cannot be done directly in Java code as {@link PiNode} is not available to the project
+ * containing {@link NodeClass}.
  */
 @ClassSubstitution(NodeClass.class)
 public class NodeClassSubstitutions {
@@ -64,12 +64,12 @@
 
     @MethodSubstitution
     private static Node getNode(Node node, long offset) {
-        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false);
+        return PiNode.piCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), Node.class, false, false);
     }
 
     @MethodSubstitution
     private static NodeList getNodeList(Node node, long offset) {
-        return UnsafeCastNode.unsafeCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false);
+        return PiNode.piCast(UnsafeLoadNode.load(node, 0, offset, Kind.Object), NodeList.class, false, false);
     }
 
     @MethodSubstitution
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/TypeCastNode.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/typesystem/TypeCastNode.java	Mon Sep 23 14:36:00 2013 -0700
@@ -62,8 +62,8 @@
     public void lower(LoweringTool tool) {
         if (graph().getGuardsStage() == StructuredGraph.GuardsStage.FLOATING_GUARDS) {
             ValueAnchorNode valueAnchorNode = graph().add(new ValueAnchorNode(null));
-            UnsafeCastNode unsafeCast = graph().unique(new UnsafeCastNode(object, this.stamp(), (GuardingNode) valueAnchorNode));
-            this.replaceAtUsages(unsafeCast);
+            PiNode piCast = graph().unique(new PiNode(object, this.stamp(), valueAnchorNode));
+            this.replaceAtUsages(piCast);
             graph().replaceFixedWithFixed(this, valueAnchorNode);
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/nodes/WordCastNode.java	Mon Sep 23 14:36:00 2013 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.word.nodes;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.word.phases.*;
+
+/**
+ * Cast between Word and Object that is introduced by the {@link WordTypeRewriterPhase}. It has an
+ * impact on the pointer maps for the GC, so it must not be scheduled or optimized away.
+ */
+public final class WordCastNode extends FixedWithNextNode implements LIRLowerable {
+
+    public static WordCastNode wordToObject(ValueNode input, Kind wordKind) {
+        assert input.kind() == wordKind;
+        return new WordCastNode(StampFactory.object(), input);
+    }
+
+    public static WordCastNode objectToWord(ValueNode input, Kind wordKind) {
+        assert input.kind() == Kind.Object;
+        return new WordCastNode(StampFactory.forKind(wordKind), input);
+    }
+
+    @Input private ValueNode input;
+
+    private WordCastNode(Stamp stamp, ValueNode input) {
+        super(stamp);
+        this.input = input;
+    }
+
+    public ValueNode getInput() {
+        return input;
+    }
+
+    @Override
+    public void generate(LIRGeneratorTool generator) {
+        assert kind() != input.kind();
+        assert generator.target().arch.getSizeInBytes(kind()) == generator.target().arch.getSizeInBytes(input.kind());
+
+        AllocatableValue result = generator.newVariable(kind());
+        generator.emitMove(result, generator.operand(input));
+        generator.setResult(this, result);
+    }
+}
--- a/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Sun Sep 22 02:24:13 2013 +0200
+++ b/graal/com.oracle.graal.word/src/com/oracle/graal/word/phases/WordTypeRewriterPhase.java	Mon Sep 23 14:36:00 2013 -0700
@@ -39,6 +39,7 @@
 import com.oracle.graal.word.*;
 import com.oracle.graal.word.Word.Opcode;
 import com.oracle.graal.word.Word.Operation;
+import com.oracle.graal.word.nodes.*;
 
 /**
  * Transforms all uses of the {@link Word} class into unsigned operations on {@code int} or
@@ -129,8 +130,6 @@
     protected void rewriteNode(StructuredGraph graph, Node node) {
         if (node instanceof CheckCastNode) {
             rewriteCheckCast(graph, (CheckCastNode) node);
-        } else if (node instanceof UnsafeCastNode) {
-            rewriteUnsafeCast(graph, (UnsafeCastNode) node);
         } else if (node instanceof LoadFieldNode) {
             rewriteLoadField(graph, (LoadFieldNode) node);
         } else if (node instanceof AccessIndexedNode) {
@@ -151,16 +150,6 @@
     }
 
     /**
-     * Remove unnecessary/redundant unsafe casts.
-     */
-    protected void rewriteUnsafeCast(StructuredGraph graph, UnsafeCastNode node) {
-        if (node.object().stamp() == node.stamp()) {
-            node.replaceAtUsages(node.object());
-            graph.removeFloating(node);
-        }
-    }
-
-    /**
      * Fold constant field reads, e.g. enum constants.
      */
     protected void rewriteLoadField(StructuredGraph graph, LoadFieldNode node) {
@@ -295,7 +284,9 @@
 
             case FROM_OBJECT:
                 assert arguments.size() == 1;
-                replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), StampFactory.forKind(wordKind))));
+                WordCastNode objectToWord = graph.add(WordCastNode.objectToWord(arguments.get(0), wordKind));
+                graph.addBeforeFixed(invoke.asNode(), objectToWord);
+                replace(invoke, objectToWord);
                 break;
 
             case FROM_ARRAY:
@@ -305,7 +296,9 @@
 
             case TO_OBJECT:
                 assert arguments.size() == 1;
-                replace(invoke, graph.unique(new UnsafeCastNode(arguments.get(0), invoke.asNode().stamp())));
+                WordCastNode wordToObject = graph.add(WordCastNode.wordToObject(arguments.get(0), wordKind));
+                graph.addBeforeFixed(invoke.asNode(), wordToObject);
+                replace(invoke, wordToObject);
                 break;
 
             default: