# HG changeset patch # User Gilles Duboscq # Date 1342181402 -7200 # Node ID ed08c40d67de64e69552c615856b9ef6c75b643a # Parent f28115ee6108d8b95053c91c35ec992f5ed63c4c 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 diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java --- 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); diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/FloatingRead2Phase.java --- /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> loopEndStatesMap; + + private static class LoopState { + public LoopBeginNode loopBegin; + public MemoryMap state; + public IdentityHashMap 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 { + private IdentityHashMap lastMemorySnapshot; + private LinkedList 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 withStates) { + if (withStates.size() == 0) { + return true; + } + Debug.log("Merge with %s", lastMemorySnapshot); + IdentityHashMap visitedKeys = new IdentityHashMap<>(); + for (MemoryMap other : withStates) { + Debug.log(" other: %s", other.lastMemorySnapshot); + for (Map.Entry 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 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 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 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(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 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 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 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); + } + } + } + } +} diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotRuntime.java --- 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) { diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/micro/FloatingReads.java --- /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)); + } +} diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.jtt/src/com/oracle/graal/jtt/optimize/Conditional01.java --- 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(); diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java --- 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); } } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/PiNode.java --- 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(); + } } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StartNode.java --- 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{ } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/ObjectEqualsNode.java --- 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())) { diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/UnsafeCastNode.java --- 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; } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/CheckCastNode.java --- 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; } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/InstanceOfNode.java --- 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; } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/ObjectStamp.java --- 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); } } diff -r f28115ee6108 -r ed08c40d67de graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/type/StampFactory.java --- 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); } }