changeset 5831:ed08c40d67de

Add a alwaysNull property to ObjectStamp (Phi(null, a! A) get a "a A" stamp and not just "a -") Add inferstamp to Pi and CheckCast to propage nonNull/alwaysNull
author Gilles Duboscq <duboscq@ssw.jku.at>
date Fri, 13 Jul 2012 14:10:02 +0200
parents f28115ee6108
children f489b0c20b56
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingRead2Phase.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/FloatingReads.java graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java
diffstat 14 files changed, 444 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Jul 13 14:10:02 2012 +0200
@@ -181,12 +181,14 @@
             new CullFrameStatesPhase().apply(graph);
         }
 
-        new FloatingReadPhase().apply(graph);
-        if (GraalOptions.OptGVN) {
-            new GlobalValueNumberingPhase().apply(graph);
-        }
-        if (GraalOptions.OptReadElimination) {
-            new ReadEliminationPhase().apply(graph);
+        if (GraalOptions.FloatingReads) {
+            Debug.dump(graph, "Before floating read");
+            int mark = graph.getMark();
+            new FloatingRead2Phase().apply(graph);
+            new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph);
+            if (GraalOptions.OptReadElimination) {
+                new ReadEliminationPhase().apply(graph);
+            }
         }
 
         if (GraalOptions.PropagateTypes) {
@@ -199,9 +201,6 @@
         if (GraalOptions.OptCanonicalizer) {
             new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
         }
-        if (GraalOptions.OptCanonicalizer) {
-            new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
-        }
 
         if (GraalOptions.OptLoopTransform) {
             new LoopTransformLowPhase().apply(graph);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingRead2Phase.java	Fri Jul 13 14:10:02 2012 +0200
@@ -0,0 +1,266 @@
+/*
+ * 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.graal.compiler.phases;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.graph.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.PhiNode.PhiType;
+import com.oracle.graal.nodes.extended.*;
+
+public class FloatingRead2Phase extends Phase {
+
+    private IdentityHashMap<LoopBeginNode, List<MemoryMap>> loopEndStatesMap;
+
+    private static class LoopState {
+        public LoopBeginNode loopBegin;
+        public MemoryMap state;
+        public IdentityHashMap<PhiNode, Object> loopPhiLocations = new IdentityHashMap<>();
+        public ValueNode loopEntryAnyLocation;
+        public LoopState(LoopBeginNode loopBegin, MemoryMap state, ValueNode loopEntryAnyLocation) {
+            this.loopBegin = loopBegin;
+            this.state = state;
+            this.loopEntryAnyLocation = loopEntryAnyLocation;
+        }
+    }
+
+    private class MemoryMap implements MergeableState<MemoryMap> {
+        private IdentityHashMap<Object, ValueNode> lastMemorySnapshot;
+        private LinkedList<LoopState> loops;
+
+        public MemoryMap(MemoryMap memoryMap) {
+            lastMemorySnapshot = new IdentityHashMap<>(memoryMap.lastMemorySnapshot);
+            loops = new LinkedList<>(memoryMap.loops);
+        }
+
+        public MemoryMap() {
+            lastMemorySnapshot = new IdentityHashMap<>();
+            loops = new LinkedList<>();
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<MemoryMap> withStates) {
+            if (withStates.size() == 0) {
+                return true;
+            }
+            Debug.log("Merge with %s", lastMemorySnapshot);
+            IdentityHashMap<Object, Object> visitedKeys = new IdentityHashMap<>();
+            for (MemoryMap other : withStates) {
+                Debug.log("  other: %s", other.lastMemorySnapshot);
+                for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
+                    Object key = entry.getKey();
+                    visitedKeys.put(key, key);
+                    ValueNode localNode = entry.getValue();
+                    ValueNode otherNode = other.lastMemorySnapshot.get(key);
+                    if (otherNode == null) {
+                        otherNode = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                    }
+                    assert localNode != null;
+                    if (localNode != otherNode && !merge.isPhiAtMerge(localNode)) {
+                        PhiNode phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
+                        phi.addInput(localNode);
+                        lastMemorySnapshot.put(key, phi);
+                    }
+                }
+            }
+            for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
+                ValueNode localNode = entry.getValue();
+                PhiNode phi = null;
+                if (merge.isPhiAtMerge(localNode)) {
+                    phi = (PhiNode) localNode;
+                } else if (!visitedKeys.containsKey(entry.getKey())) {
+                    phi = merge.graph().add(new PhiNode(PhiType.Memory, merge));
+                    phi.addInput(localNode);
+                    lastMemorySnapshot.put(entry.getKey(), phi);
+                }
+                if (phi != null) {
+                    Debug.log("Phi @ %s for %s", merge, entry.getKey());
+                    for (MemoryMap other : withStates) {
+                        ValueNode otherNode = other.lastMemorySnapshot.get(entry.getKey());
+                        if (otherNode == null) {
+                            otherNode = other.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                        }
+                        assert otherNode != null;
+                        phi.addInput(otherNode);
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+            LoopState loopState = new LoopState(loopBegin, this, lastMemorySnapshot.get(LocationNode.ANY_LOCATION));
+            for (Map.Entry<Object, ValueNode> entry : lastMemorySnapshot.entrySet()) {
+                PhiNode phi = loopBegin.graph().add(new PhiNode(PhiType.Memory, loopBegin));
+                phi.addInput(entry.getValue());
+                entry.setValue(phi);
+                loopState.loopPhiLocations.put(phi, entry.getKey());
+            }
+            loops.push(loopState);
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<MemoryMap> loopEndStates) {
+            loopEndStatesMap.put(loopBegin, loopEndStates);
+            tryFinishLoopPhis(this, loopBegin);
+        }
+
+        @Override
+        public void afterSplit(FixedNode node) {
+            // nothing
+        }
+
+        @Override
+        public MemoryMap clone() {
+            return new MemoryMap(this);
+        }
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        loopEndStatesMap = new IdentityHashMap<>();
+        new PostOrderNodeIterator<MemoryMap>(graph.start(), new MemoryMap()) {
+            @Override
+            protected void node(FixedNode node) {
+                processNode(node, state);
+            }
+        }.apply();
+    }
+
+    private void processNode(FixedNode node, MemoryMap state) {
+        if (node instanceof ReadNode) {
+            processRead((ReadNode) node, state);
+        } else if (node instanceof WriteNode) {
+            processWrite((WriteNode) node, state);
+        } else if (node instanceof MemoryCheckpoint) {
+            processCheckpoint((MemoryCheckpoint) node, state);
+        } else if (node instanceof LoopExitNode) {
+            processLoopExit((LoopExitNode) node, state);
+        }
+    }
+
+    private static void processCheckpoint(MemoryCheckpoint checkpoint, MemoryMap state) {
+        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
+            entry.setValue((ValueNode) checkpoint);
+        }
+        state.lastMemorySnapshot.put(LocationNode.ANY_LOCATION, (ValueNode) checkpoint);
+    }
+
+    private static void processWrite(WriteNode writeNode, MemoryMap state) {
+        if (writeNode.location().locationIdentity() == LocationNode.ANY_LOCATION) {
+            state.lastMemorySnapshot.clear();
+        }
+        state.lastMemorySnapshot.put(writeNode.location().locationIdentity(), writeNode);
+    }
+
+    private void processRead(ReadNode readNode, MemoryMap state) {
+        StructuredGraph graph = (StructuredGraph) readNode.graph();
+        assert readNode.getNullCheck() == false;
+        Object locationIdentity = readNode.location().locationIdentity();
+        ValueNode lastLocationAccess = getLastLocationAccessForRead(state, locationIdentity);
+        FloatingReadNode floatingRead = graph.unique(new FloatingReadNode(readNode.object(), readNode.location(), lastLocationAccess, readNode.stamp(), readNode.dependencies()));
+        floatingRead.setNullCheck(readNode.getNullCheck());
+        ValueAnchorNode anchor = null;
+        for (GuardNode guard : readNode.dependencies().filter(GuardNode.class)) {
+            if (anchor == null) {
+                anchor = graph.add(new ValueAnchorNode());
+            }
+            anchor.addAnchoredNode(guard);
+        }
+        if (anchor != null) {
+            graph.addAfterFixed(readNode, anchor);
+        }
+        graph.replaceFixedWithFloating(readNode, floatingRead);
+    }
+
+    private ValueNode getLastLocationAccessForRead(MemoryMap state, Object locationIdentity) {
+        ValueNode lastLocationAccess;
+        if (locationIdentity == LocationNode.FINAL_LOCATION) {
+            lastLocationAccess = null;
+        } else {
+            lastLocationAccess = state.lastMemorySnapshot.get(locationIdentity);
+            if (lastLocationAccess == null) {
+                LoopState lastLoop = state.loops.peek();
+                if (lastLoop == null) {
+                    lastLocationAccess = state.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                    Debug.log("getLastLocationAccessForRead(%s, %s) -> unknown, not in a loop : %s", state, locationIdentity, lastLocationAccess);
+                } else {
+                    ValueNode phiInit;
+                    if (state.loops.size() > 1) {
+                        Debug.log("getLastLocationAccessForRead(%s, %s) -> unknown, in a non-outtermost loop, getting state in 2nd loop", state, locationIdentity);
+                        phiInit = getLastLocationAccessForRead(state.loops.get(1).state, locationIdentity);
+                    } else {
+                        phiInit = lastLoop.loopEntryAnyLocation;
+                        Debug.log("getLastLocationAccessForRead(%s, %s) -> unknown, in a outtermost loop : Phi(%s,...)", state, locationIdentity, phiInit);
+                    }
+                    PhiNode phi = lastLoop.loopBegin.graph().add(new PhiNode(PhiType.Memory, lastLoop.loopBegin));
+                    phi.addInput(phiInit);
+                    lastLoop.state.lastMemorySnapshot.put(locationIdentity, phi);
+                    lastLoop.loopPhiLocations.put(phi, locationIdentity);
+                    tryFinishLoopPhis(lastLoop.state, lastLoop.loopBegin);
+                    lastLocationAccess = phi;
+                }
+                state.lastMemorySnapshot.put(locationIdentity, lastLocationAccess);
+            } else {
+                Debug.log("getLastLocationAccessForRead(%s, %s) -> directly : %s", state, locationIdentity, lastLocationAccess);
+            }
+        }
+        return lastLocationAccess;
+    }
+
+    private static void processLoopExit(LoopExitNode exit, MemoryMap state) {
+        for (Map.Entry<Object, ValueNode> entry : state.lastMemorySnapshot.entrySet()) {
+            entry.setValue(exit.graph().unique(new ValueProxyNode(entry.getValue(), exit, PhiType.Memory)));
+        }
+        LoopState poped = state.loops.pop();
+        assert poped.loopBegin == exit.loopBegin();
+    }
+
+    private void tryFinishLoopPhis(MemoryMap loopMemory, LoopBeginNode loopBegin) {
+        List<MemoryMap> loopEndStates = loopEndStatesMap.get(loopBegin);
+        if (loopEndStates == null) {
+            return;
+        }
+        LoopState loopState = loopMemory.loops.get(0);
+        int i = 0;
+        while (loopState.loopBegin != loopBegin) {
+            loopState = loopMemory.loops.get(++i);
+        }
+        for (PhiNode phi : loopBegin.phis()) {
+            if (phi.type() == PhiType.Memory && phi.valueCount() == 1) {
+                Object location = loopState.loopPhiLocations.get(phi);
+                assert location != null : "unknown location for " + phi;
+                for (MemoryMap endState : loopEndStates) {
+                    ValueNode otherNode = endState.lastMemorySnapshot.get(location);
+                    if (otherNode == null) {
+                        otherNode = endState.lastMemorySnapshot.get(LocationNode.ANY_LOCATION);
+                    }
+                    phi.addInput(otherNode);
+                }
+            }
+        }
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java	Fri Jul 13 14:10:02 2012 +0200
@@ -253,7 +253,7 @@
             graph.replaceFixedWithFixed(storeField, memoryWrite);
 
             FixedWithNextNode last = memoryWrite;
-            if (field.kind() == Kind.Object && !memoryWrite.value().isNullConstant()) {
+            if (field.kind() == Kind.Object && !memoryWrite.value().objectStamp().alwaysNull()) {
                 FieldWriteBarrier writeBarrier = graph.add(new FieldWriteBarrier(memoryWrite.object()));
                 graph.addAfterFixed(memoryWrite, writeBarrier);
                 last = writeBarrier;
@@ -268,7 +268,7 @@
             // Separate out GC barrier semantics
             CompareAndSwapNode cas = (CompareAndSwapNode) n;
             ValueNode expected = cas.expected();
-            if (expected.kind() == Kind.Object && !cas.newValue().isNullConstant()) {
+            if (expected.kind() == Kind.Object && !cas.newValue().objectStamp().alwaysNull()) {
                 ResolvedJavaType type = cas.object().objectStamp().type();
                 if (type != null && !type.isArrayClass() && type.toJava() != Object.class) {
                     // Use a field write barrier since it's not an array store
@@ -299,7 +299,7 @@
             ValueNode value = storeIndexed.value();
             CheckCastNode checkcast = null;
             ValueNode array = storeIndexed.array();
-            if (elementKind == Kind.Object && !value.isNullConstant()) {
+            if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) {
                 // Store check!
                 ResolvedJavaType arrayType = array.objectStamp().type();
                 if (arrayType != null && array.objectStamp().isExactType()) {
@@ -328,7 +328,7 @@
 
             graph.replaceFixedWithFixed(storeIndexed, memoryWrite);
 
-            if (elementKind == Kind.Object && !value.isNullConstant()) {
+            if (elementKind == Kind.Object && !value.objectStamp().alwaysNull()) {
                 graph.addAfterFixed(memoryWrite, graph.add(new ArrayWriteBarrier(array, arrayLocation)));
             }
         } else if (n instanceof UnsafeLoadNode) {
@@ -347,7 +347,7 @@
             WriteNode write = graph.add(new WriteNode(object, store.value(), location));
             write.setStateAfter(store.stateAfter());
             graph.replaceFixedWithFixed(store, write);
-            if (write.value().kind() == Kind.Object && !write.value().isNullConstant()) {
+            if (write.value().kind() == Kind.Object && !write.value().objectStamp().alwaysNull()) {
                 ResolvedJavaType type = object.objectStamp().type();
                 WriteBarrier writeBarrier;
                 if (type != null && !type.isArrayClass() && type.toJava() != Object.class) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/FloatingReads.java	Fri Jul 13 14:10:02 2012 +0200
@@ -0,0 +1,83 @@
+/*
+ * 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.jtt.micro;
+
+import org.junit.*;
+
+
+public class FloatingReads {
+    private static long init = Runtime.getRuntime().totalMemory();
+    private final int f = 10;
+    private int a;
+    private int b;
+    private int c;
+
+    public int test(int d) {
+        a = 3;
+        b = 5;
+        c = 7;
+        for (int i = 0; i < d; i++) {
+            if (i % 2 == 0) {
+                a += b;
+            }
+            if (i % 4 == 0) {
+                b += c;
+            } else if (i % 3 == 0) {
+                b -= a;
+            }
+            if (i % 5 == 0) {
+                for (int j = 0; j < i; j++) {
+                    c += a;
+                }
+                a -= f;
+            }
+            b = a ^ c;
+            if (i % 6 == 0) {
+                c--;
+            } else if (i % 7 == 0) {
+                Runtime.getRuntime().totalMemory();
+            }
+        }
+        return a + b + c;
+    }
+
+    @Test
+    public void run0() {
+        Assert.assertEquals(-42, test(10));
+    }
+
+    @Test
+    public void run1() {
+        Assert.assertEquals(2147465134, test(1000));
+    }
+
+    @Test
+    public void run2() {
+        Assert.assertEquals(-3, test(1));
+    }
+
+    @Test
+    public void run3() {
+        Assert.assertEquals(15, test(0));
+    }
+}
--- a/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java	Fri Jul 13 14:10:02 2012 +0200
@@ -30,8 +30,10 @@
  */
 @SuppressWarnings("unused")
 public class Conditional01 {
-
     private static final int RAM_SIZE = 0x100;
+    private static final int init = new Random().nextInt();
+    private static final int init1 = new Register().val;
+    private static final Register init2 = new CPC().r1;
 
     public static int test(int arg) {
         Conditional01 c = new Conditional01();
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -71,6 +71,7 @@
         } else {
             // This begin node can be removed and all guards moved up to the preceding begin node.
             prepareDelete();
+            tool.addToWorkList(next());
             ((StructuredGraph) graph()).removeFixed(this);
         }
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -50,4 +50,17 @@
     public void generate(LIRGeneratorTool generator) {
         generator.setResult(this, generator.operand(object));
     }
+
+    @Override
+    public boolean inferStamp() {
+        if (object().stamp().nonNull() && !stamp().nonNull()) {
+            setStamp(StampFactory.declaredNonNull(objectStamp().type()));
+            return true;
+        }
+        if (object().objectStamp().alwaysNull() && !objectStamp().alwaysNull()) {
+            setStamp(StampFactory.alwaysNull());
+            return true;
+        }
+        return super.inferStamp();
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -22,9 +22,11 @@
  */
 package com.oracle.graal.nodes;
 
+import com.oracle.graal.nodes.extended.*;
+
 /**
  * The start node of a graph.
  */
-public class StartNode extends BeginStateSplitNode {
+public class StartNode extends BeginStateSplitNode implements MemoryCheckpoint{
 
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -58,9 +58,9 @@
             return ConstantNode.forBoolean(true, graph());
         }
 
-        if (x().isNullConstant()) {
+        if (x().objectStamp().alwaysNull()) {
             return graph().unique(new IsNullNode(y()));
-        } else if (y().isNullConstant()) {
+        } else if (y().objectStamp().alwaysNull()) {
             return graph().unique(new IsNullNode(x()));
         }
         if (x().stamp().alwaysDistinct(y().stamp())) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -41,7 +41,7 @@
     }
 
     public UnsafeCastNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
-        super(toType.kind().isObject() ? new ObjectStamp(toType, exactType, nonNull) : StampFactory.forKind(toType.kind()));
+        super(toType.kind().isObject() ? new ObjectStamp(toType, exactType, nonNull, false) : StampFactory.forKind(toType.kind()));
         this.object = object;
         this.toType = toType;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -51,7 +51,7 @@
     }
 
     public CheckCastNode(ValueNode targetClassInstruction, ResolvedJavaType targetClass, ValueNode object, JavaTypeProfile profile) {
-        super(targetClass == null ? StampFactory.forKind(Kind.Object) : StampFactory.declared(targetClass));
+        super(targetClass == null ? StampFactory.object() : StampFactory.declared(targetClass));
         this.targetClassInstruction = targetClassInstruction;
         this.targetClass = targetClass;
         this.object = object;
@@ -69,6 +69,15 @@
     }
 
     @Override
+    public boolean inferStamp() {
+        if (object().stamp().nonNull() && !stamp().nonNull()) {
+            setStamp(targetClass == null ? StampFactory.objectNonNull() : StampFactory.declaredNonNull(targetClass));
+            return true;
+        }
+        return super.inferStamp();
+    }
+
+    @Override
     public ValueNode canonical(CanonicalizerTool tool) {
         assert object() != null : this;
 
@@ -80,12 +89,8 @@
             }
         }
 
-        Constant constant = object().asConstant();
-        if (constant != null) {
-            assert constant.kind == Kind.Object;
-            if (constant.isNull()) {
-                return object();
-            }
+        if (object().objectStamp().alwaysNull()) {
+            return object();
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java	Fri Jul 13 14:10:02 2012 +0200
@@ -103,15 +103,8 @@
                 // since the subtype comparison was only performed on a declared type we don't really know if it might be true at run time...
             }
         }
-
-        Constant constant = object().asConstant();
-        if (constant != null) {
-            assert constant.kind == Kind.Object;
-            if (constant.isNull()) {
-                return ConstantNode.forBoolean(false, graph());
-            } else {
-                assert false : "non-null constants are always expected to provide an exact type";
-            }
+        if (object().objectStamp().alwaysNull()) {
+            return ConstantNode.forBoolean(false, graph());
         }
         return this;
     }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java	Fri Jul 13 14:10:02 2012 +0200
@@ -30,13 +30,16 @@
     private final ResolvedJavaType type;
     private final boolean exactType;
     private final boolean nonNull;
+    private final boolean alwaysNull;
 
-    public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull) {
+    public ObjectStamp(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean alwaysNull) {
         super(Kind.Object);
         assert !exactType || type != null;
+        assert !(nonNull && alwaysNull);
         this.type = type;
         this.exactType = exactType;
         this.nonNull = nonNull;
+        this.alwaysNull = alwaysNull;
     }
 
     @Override
@@ -44,6 +47,10 @@
         return nonNull;
     }
 
+    public boolean alwaysNull() {
+        return alwaysNull;
+    }
+
     public ResolvedJavaType type() {
         return type;
     }
@@ -56,13 +63,16 @@
     public String toString() {
         StringBuilder str = new StringBuilder();
         str.append(kind().typeChar);
-        str.append(nonNull ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.name());
+        str.append(nonNull ? "!" : "").append(exactType ? "#" : "").append(' ').append(type == null ? "-" : type.name()).append(alwaysNull ? " NULL" : "");
         return str.toString();
     }
 
     @Override
     public boolean alwaysDistinct(Stamp otherStamp) {
         ObjectStamp other = (ObjectStamp) otherStamp;
+        if ((alwaysNull && other.nonNull) || (nonNull && other.alwaysNull)) {
+            return true;
+        }
         if (other.type == null || type == null) {
             // We have no type information for one of the values.
             return false;
@@ -76,14 +86,31 @@
     @Override
     public Stamp meet(Stamp otherStamp) {
         ObjectStamp other = (ObjectStamp) otherStamp;
-        ResolvedJavaType orType = meetTypes(type(), other.type());
-        boolean meetExactType = orType == type && orType == other.type && exactType && other.exactType;
-        boolean meetNonNull = nonNull && other.nonNull;
+        ResolvedJavaType meetType;
+        boolean meetExactType;
+        boolean meetNonNull;
+        boolean meetAlwaysNull;
+        if (other.alwaysNull) {
+            meetType = type();
+            meetExactType = exactType;
+            meetNonNull = false;
+            meetAlwaysNull = alwaysNull;
+        } else if (alwaysNull) {
+            meetType = other.type();
+            meetExactType = other.exactType;
+            meetNonNull = false;
+            meetAlwaysNull = other.alwaysNull;
+        } else {
+            meetType = meetTypes(type(), other.type());
+            meetExactType = meetType == type && meetType == other.type && exactType && other.exactType;
+            meetNonNull = nonNull && other.nonNull;
+            meetAlwaysNull = false;
+        }
 
-        if (orType == type && meetExactType == exactType && meetNonNull == nonNull) {
+        if (meetType == type && meetExactType == exactType && meetNonNull == nonNull && meetAlwaysNull == alwaysNull) {
             return this;
         } else {
-            return new ObjectStamp(orType, meetExactType, meetNonNull);
+            return new ObjectStamp(meetType, meetExactType, meetNonNull, meetAlwaysNull);
         }
     }
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri Jul 13 11:29:15 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java	Fri Jul 13 14:10:02 2012 +0200
@@ -29,8 +29,9 @@
 
 public class StampFactory {
     private static final Stamp[] stampCache = new Stamp[Kind.values().length];
-    private static final Stamp objectStamp = new ObjectStamp(null, false, false);
-    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true);
+    private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
+    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
+    private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
     private static final Stamp dependencyStamp = new GenericStamp(GenericStampType.Dependency);
     private static final Stamp extensionStamp = new GenericStamp(GenericStampType.Extension);
     private static final Stamp virtualStamp = new GenericStamp(GenericStampType.Virtual);
@@ -123,7 +124,7 @@
         assert value.kind == Kind.Object;
         if (value.kind == Kind.Object) {
             ResolvedJavaType type = value.isNull() ? null : runtime.getTypeOf(value);
-            return new ObjectStamp(type, value.isNonNull(), value.isNonNull());
+            return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
         } else {
             throw new GraalInternalError(Kind.Object + " expected, actual kind: %s", value.kind);
         }
@@ -137,6 +138,10 @@
         return objectNonNullStamp;
     }
 
+    public static Stamp alwaysNull() {
+        return objectAlwaysNullStamp;
+    }
+
     public static Stamp declared(ResolvedJavaType type) {
         return declared(type, false);
     }
@@ -150,13 +155,13 @@
         assert type.kind() == Kind.Object;
         ResolvedJavaType exact = type.exactType();
         if (exact != null) {
-            return new ObjectStamp(exact, true, nonNull);
+            return new ObjectStamp(exact, true, nonNull, false);
         } else {
-            return new ObjectStamp(type, false, nonNull);
+            return new ObjectStamp(type, false, nonNull, false);
         }
     }
 
     public static Stamp exactNonNull(ResolvedJavaType type) {
-        return new ObjectStamp(type, true, true);
+        return new ObjectStamp(type, true, true, false);
     }
 }