changeset 5085:5bdaa08ba96b

add and enable new PropagateTypeCachePhase, add type system tests
author Lukas Stadler <lukas.stadler@jku.at>
date Wed, 14 Mar 2012 17:59:06 +0100
parents 77aa8141ba41
children ed53c5f8244b
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypesPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java
diffstat 11 files changed, 588 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Wed Mar 14 17:59:06 2012 +0100
@@ -150,7 +150,7 @@
                 new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
             }
 
-            new PropagateTypesPhase(target, runtime, assumptions).apply(graph);
+            new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
         }
 
         if (GraalOptions.Inline && !plan.isPhaseDisabled(InliningPhase.class)) {
@@ -164,7 +164,7 @@
         }
 
         if (GraalOptions.PropagateTypes) {
-            new PropagateTypesPhase(target, runtime, assumptions).apply(graph);
+            new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
         }
 
         plan.runPhases(PhasePosition.HIGH_LEVEL, graph);
@@ -198,6 +198,13 @@
                 new ReadEliminationPhase().apply(graph);
             }
         }
+
+        if (GraalOptions.PropagateTypes) {
+            new PropagateTypeCachePhase(target, runtime, assumptions).apply(graph);
+        }
+        if (GraalOptions.OptGVN) {
+            new GlobalValueNumberingPhase().apply(graph);
+        }
         new DeadCodeEliminationPhase().apply(graph);
 
         plan.runPhases(PhasePosition.MID_LEVEL, graph);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Wed Mar 14 17:59:06 2012 +0100
@@ -147,7 +147,7 @@
     public static boolean AssumeVerifiedBytecode             = true;
 
     // Code generator settings
-    public static boolean PropagateTypes                     = ____;
+    public static boolean PropagateTypes                     = true;
     public static boolean UseBranchPrediction                = true;
     public static boolean UseExceptionProbability            = true;
     public static boolean AllowExplicitExceptionChecks       = true;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypeCachePhase.java	Wed Mar 14 17:59:06 2012 +0100
@@ -0,0 +1,290 @@
+/*
+ * 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.compiler.types;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.schedule.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.spi.types.*;
+import com.oracle.graal.nodes.spi.types.TypeCanonicalizable.Result;
+
+public class PropagateTypeCachePhase extends Phase {
+
+    private static final boolean DUMP = false;
+
+    private final CiTarget target;
+    private final RiRuntime runtime;
+    private final CiAssumptions assumptions;
+
+    private NodeWorkList changedNodes;
+    private StructuredGraph currentGraph;
+    private SchedulePhase schedule;
+
+    private TypeFeedbackChanged changed = new TypeFeedbackChanged();
+    private static PrintStream out = System.out;
+
+    private int changes = 0;
+
+//    private static int totalChanges = 0;
+//
+//    static {
+//        Runtime.getRuntime().addShutdownHook(new Thread() {
+//            @Override
+//            public void run() {
+//                System.out.println("Total changes: " + totalChanges);
+//            }
+//        });
+//    }
+
+    public PropagateTypeCachePhase(CiTarget target, RiRuntime runtime, CiAssumptions assumptions) {
+        this.target = target;
+        this.runtime = runtime;
+        this.assumptions = assumptions;
+    }
+
+    @Override
+    protected void run(StructuredGraph graph) {
+
+// if (!graph.method().holder().name().contains("IntegerAddNode") || !graph.method().name().equals("canonical")) {
+// return;
+// }
+
+// if (!graph.method().name().equals("notifySourceElementRequestor")) {
+// return;
+// }
+
+//        if (graph.method().holder().name().contains("jj_3R_75")) {
+//            return;
+//        }
+
+        this.currentGraph = graph;
+        new DeadCodeEliminationPhase().apply(graph);
+
+        for (GuardNode guard : graph.getNodes(GuardNode.class)) {
+            if (guard.condition() != null && guard.condition().usages().size() > 1) {
+                BooleanNode clone = (BooleanNode) guard.condition().copyWithInputs();
+                if (DUMP) {
+                    out.println("replaced!! " + clone);
+                }
+                guard.setCondition(clone);
+            }
+        }
+        for (FixedGuardNode guard : graph.getNodes(FixedGuardNode.class)) {
+            for (int i = 0; i < guard.conditions().size(); i++) {
+                BooleanNode condition = guard.conditions().get(i);
+                if (condition != null && condition.usages().size() > 1) {
+                    BooleanNode clone = (BooleanNode) condition.copyWithInputs();
+                    if (DUMP) {
+                        out.println("replaced!! " + clone);
+                    }
+                    guard.conditions().set(i, clone);
+                }
+            }
+        }
+
+        changedNodes = graph.createNodeWorkList(false, 10);
+
+        schedule = new SchedulePhase();
+        schedule.apply(graph);
+
+        new Iterator().apply(schedule.getCFG().getStartBlock());
+
+        Debug.dump(graph, "After PropagateType iteration");
+        if (changes > 0) {
+//            totalChanges += changes;
+//            out.println(graph.method() + ": " + changes + " changes");
+        }
+
+        CanonicalizerPhase.canonicalize(graph, changedNodes, runtime, target, assumptions);
+// outputGraph(graph);
+    }
+
+    public void outputGraph(StructuredGraph graph) {
+        SchedulePhase printSchedule = new SchedulePhase();
+        printSchedule.apply(graph);
+        for (Block block : printSchedule.getCFG().getBlocks()) {
+            System.out.print("Block " + block + " ");
+            if (block == printSchedule.getCFG().getStartBlock()) {
+                out.print("* ");
+            }
+            System.out.print("-> ");
+            for (Block succ : block.getSuccessors()) {
+                out.print(succ + " ");
+            }
+            System.out.println();
+            for (Node node : printSchedule.getNodesFor().get(block)) {
+                out.println("  " + node + "    (" + node.usages().size() + ")");
+            }
+        }
+    }
+
+    private class Iterator extends PostOrderBlockIterator {
+
+        private final HashMap<Block, TypeFeedbackCache> caches = new HashMap<>();
+
+        @Override
+        protected void block(Block block) {
+            if (DUMP) {
+                out.println("======= block B" + block.getId());
+            }
+            final TypeFeedbackCache cache;
+            if (block.getPredecessors().isEmpty()) {
+                cache = new TypeFeedbackCache(runtime, currentGraph, changed);
+            } else {
+                if (block.getPredecessors().size() == 1) {
+                    cache = caches.get(block.getPredecessors().get(0)).clone();
+                    Node lastInstruction = block.getPredecessors().get(0).getEndNode();
+                    if (lastInstruction instanceof ControlSplitNode && lastInstruction instanceof SplitTypeFeedbackProvider) {
+                        ControlSplitNode split = (ControlSplitNode) lastInstruction;
+                        int successorIndex = -1;
+                        for (int i = 0; i < split.blockSuccessorCount(); i++) {
+                            if (split.blockSuccessor(i) == block.getBeginNode()) {
+                                successorIndex = i;
+                                break;
+                            }
+                        }
+                        assert successorIndex != -1;
+                        changed.node = block.getBeginNode();
+                        ((SplitTypeFeedbackProvider) split).typeFeedback(successorIndex, cache);
+                        if (DUMP) {
+                            out.println("split (edge " + successorIndex + ") " + split + ": " + cache);
+                        }
+                        changed.node = null;
+                    }
+                } else {
+                    TypeFeedbackCache[] cacheList = new TypeFeedbackCache[block.getPredecessors().size()];
+                    MergeNode merge = (MergeNode) block.getBeginNode();
+                    for (int i = 0; i < block.getPredecessors().size(); i++) {
+                        Block predecessor = block.getPredecessors().get(i);
+                        TypeFeedbackCache other = caches.get(predecessor);
+                        int endIndex = merge.forwardEndIndex((EndNode) predecessor.getEndNode());
+                        cacheList[endIndex] = other;
+                    }
+                    changed.node = merge;
+                    cache = TypeFeedbackCache.meet(cacheList, merge.phis());
+                    changed.node = null;
+                    if (DUMP) {
+                        out.println("merge " + merge + ": " + cache);
+                    }
+                }
+            }
+            processNodes(block, cache);
+        }
+
+        private void processNodes(Block block, TypeFeedbackCache cache) {
+            for (Node node : schedule.nodesFor(block)) {
+                if (node.isAlive()) {
+                    if (DUMP) {
+                        out.println(node);
+                    }
+                    if (node instanceof TypeCanonicalizable) {
+                        Result canonical = ((TypeCanonicalizable) node).canonical(cache);
+
+                        if (canonical != null) {
+                            changes++;
+// System.out.print("!");
+                            if (DUMP) {
+                                out.println("TypeCanonicalizable: replacing " + node + " with " + canonical);
+                            }
+                            if (canonical.dependencies.length > 0) {
+                                for (Node usage : node.usages()) {
+                                    if (usage instanceof ValueNode) {
+                                        for (Node dependency : canonical.dependencies) {
+                                            // TODO(lstadler) dead dependencies should be handled differently
+                                            if (dependency.isAlive()) {
+                                                ((ValueNode) usage).dependencies().add(dependency);
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                            ValueNode replacement = canonical.replacement;
+                            currentGraph.replaceFloating((FloatingNode) node, replacement);
+                            changedNodes.addAll(replacement.usages());
+                        }
+                    }
+                    if (node.isAlive() && node instanceof TypeFeedbackProvider) {
+                        changed.node = node;
+                        ((TypeFeedbackProvider) node).typeFeedback(cache);
+                        if (DUMP) {
+                            out.println("  " + cache);
+                        }
+                        changed.node = null;
+                    }
+                }
+            }
+            caches.put(block, cache);
+        }
+
+        @Override
+        protected void loopHeaderInitial(Block block) {
+            if (DUMP) {
+                out.println("======= loop block B" + block.getId());
+            }
+            assert block.getPredecessors().get(0) == block.getDominator();
+            TypeFeedbackCache cache = caches.get(block.getPredecessors().get(0)).clone();
+            processNodes(block, cache);
+        }
+
+        @Override
+        protected boolean loopHeader(Block block, int loopVisitedCount) {
+            if (DUMP) {
+                out.println("======= loop again block B" + block.getId());
+            }
+            if (loopVisitedCount == 1) {
+                TypeFeedbackCache[] cacheList = new TypeFeedbackCache[block.getPredecessors().size()];
+                LoopBeginNode loop = (LoopBeginNode) block.getBeginNode();
+                for (int i = 0; i < block.getPredecessors().size(); i++) {
+                    Block predecessor = block.getPredecessors().get(i);
+                    TypeFeedbackCache other = caches.get(predecessor);
+                    int endIndex;
+                    if (loop.forwardEnd() == predecessor.getEndNode()) {
+                        endIndex = 0;
+                    } else {
+                        endIndex = loop.orderedLoopEnds().indexOf(predecessor.getEndNode()) + 1;
+                        assert endIndex != 0;
+                    }
+                    cacheList[endIndex] = other;
+                }
+                TypeFeedbackCache cache = TypeFeedbackCache.meet(cacheList, loop.phis());
+                if (DUMP) {
+                    out.println("loop merge " + loop + ": " + cache);
+                }
+                processNodes(block, cache);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypesPhase.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/types/PropagateTypesPhase.java	Wed Mar 14 17:59:06 2012 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -39,6 +39,7 @@
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
 
 public class PropagateTypesPhase extends Phase {
 
@@ -56,7 +57,7 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-
+/*
         new DeadCodeEliminationPhase().apply(graph);
 
         changedNodes = graph.createNodeWorkList(false, 10);
@@ -72,9 +73,9 @@
 
         new UnscheduleNodes(graph.start()).apply();
 
-        CanonicalizerPhase.canonicalize(graph, changedNodes, runtime, target, assumptions);
+        CanonicalizerPhase.canonicalize(graph, changedNodes, runtime, target, assumptions);*/
     }
-
+/*
     private class PiNodeList {
 
         public final PiNodeList last;
@@ -104,6 +105,48 @@
         }
     }
 
+    private static RiResolvedType mergeSuperType(RiResolvedType type1, RiResolvedType type2) {
+        Set<RiResolvedType> superTypes = new HashSet<>();
+
+        RiResolvedType current = type1;
+        while (current != null) {
+            superTypes.add(current);
+            current = current.superType();
+        }
+
+        current = type2;
+        while (current != null) {
+            if (superTypes.contains(current)) {
+                return current;
+            }
+            current = current.superType();
+        }
+
+        return null;
+    }
+
+    private static RiResolvedType mergeType(RiResolvedType type1, RiResolvedType type2) {
+        if (type1 == null || type2 == null) {
+            return null;
+        }
+        if (type1.isInterface() && !type2.isInterface()) {
+            if (type1.toJava().isAssignableFrom(type2.toJava())) {
+                return type1;
+            } else {
+                return null;
+            }
+        } else if (type2.isInterface() && !type1.isInterface()) {
+            if (type2.toJava().isAssignableFrom(type1.toJava())) {
+                return type2;
+            } else {
+                return null;
+            }
+        } else {
+            // both are either types or interfaces
+            return mergeSuperType(type1, type2);
+        }
+    }
+
     private class TypeInfo implements MergeableState<TypeInfo> {
 
         private HashMap<ValueNode, PiNodeList> piNodes = new HashMap<>();
@@ -112,6 +155,16 @@
             this.piNodes.putAll(piNodes);
         }
 
+        public ValueNode getNode(ValueNode value) {
+            PiNodeList list = piNodes.get(value);
+            if (list == null) {
+                return value;
+            } else {
+                return list.replacement;
+            }
+        }
+
+
         @Override
         public TypeInfo clone() {
             return new TypeInfo(piNodes);
@@ -138,6 +191,28 @@
                         newPiNodes.put(entry.getKey(), list);
                     }
                 }
+
+                for (PhiNode phi : merge.phis()) {
+                    if (phi.kind() == CiKind.Object && phi.valueCount() == (withStates.size() + 1)) {
+                        ValueNode node = getNode(phi.valueAt(0));
+                        RiResolvedType type = node.declaredType();
+                        boolean nonNull = node.stamp().nonNull();
+                        for (int i = 1; i < phi.valueCount(); i++) {
+                            node = withStates.get(i - 1).getNode(phi.valueAt(i));
+                            type = mergeType(type, node.declaredType());
+                            nonNull &= node.stamp().nonNull();
+                        }
+                        if (type != null) {
+                            if (nonNull) {
+                                phi.setStamp(StampFactory.declaredNonNull(type));
+                            } else {
+                                phi.setStamp(StampFactory.declared(type));
+                            }
+                        } else if (nonNull) {
+                            phi.setStamp(StampFactory.objectNonNull());
+                        }
+                    }
+                }
                 piNodes = newPiNodes;
             }
             return true;
@@ -166,7 +241,7 @@
                         if (value.declaredType() != instanceOf.targetClass() || !value.stamp().nonNull()) {
                             PiNode piNode = node.graph().unique(new PiNode(value, (BeginNode) node, StampFactory.declaredNonNull(instanceOf.targetClass())));
                             PiNodeList list = piNodes.get(value);
-                            piNodes.put(value, new PiNodeList(piNode, list));
+                            piNodes.put(GraphUtil.producingInstruction(value), new PiNodeList(piNode, list));
                         }
                     }
                 } else if (ifNode.compare() instanceof CompareNode) {
@@ -176,7 +251,7 @@
                         if (compare.y().isConstant()) {
                             ValueNode value = compare.x();
                             PiNodeList list = piNodes.get(value);
-                            piNodes.put(value, new PiNodeList(compare.y(), list));
+                            piNodes.put(GraphUtil.producingInstruction(value), new PiNodeList(compare.y(), list));
                         }
                     } else if ((node == ifNode.trueSuccessor() && compare.condition() == Condition.NE) || (node == ifNode.falseSuccessor() && compare.condition() == Condition.EQ)) {
                         if (!compare.x().isConstant() && compare.y().isNullConstant() && !compare.x().stamp().nonNull()) {
@@ -190,7 +265,7 @@
                                 piNode = node.graph().unique(new PiNode(value, (BeginNode) node, StampFactory.objectNonNull()));
                             }
                             PiNodeList list = piNodes.get(value);
-                            piNodes.put(value, new PiNodeList(piNode, list));
+                            piNodes.put(GraphUtil.producingInstruction(value), new PiNodeList(piNode, list));
                         }
                     }
                 }
@@ -225,13 +300,14 @@
 
         @Override
         protected void node(ScheduledNode node) {
+
             if (node instanceof Canonicalizable || node instanceof Invoke) {
                 NodeClassIterator iter = node.inputs().iterator();
                 ArrayList<Node> changedInputs = new ArrayList<>();
                 while (iter.hasNext()) {
                     Position pos = iter.nextPosition();
                     Node value = pos.get(node);
-                    PiNodeList list = state.piNodes.get(value);
+                    PiNodeList list = value == null ? null : state.piNodes.get(GraphUtil.producingInstruction(value));
                     if (list != null) {
                         changedInputs.add(list.replacement instanceof PiNode ? value : null);
                         pos.set(node, list.replacement);
@@ -261,4 +337,5 @@
             }
         }
     }
+    */
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/ConstantNode.java	Wed Mar 14 17:59:06 2012 +0100
@@ -39,7 +39,8 @@
     @Data public final CiConstant value;
 
     protected ConstantNode(CiConstant value) {
-        this(value, null);
+        super(StampFactory.forConstant(value));
+        this.value = value;
     }
 
     /**
@@ -65,7 +66,11 @@
     }
 
     public static ConstantNode forCiConstant(CiConstant constant, RiRuntime runtime, Graph graph) {
-        return graph.unique(new ConstantNode(constant, runtime));
+        if (constant.kind == CiKind.Object) {
+            return graph.unique(new ConstantNode(constant, runtime));
+        } else {
+            return graph.unique(new ConstantNode(constant));
+        }
     }
 
     /**
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/FixedGuardNode.java	Wed Mar 14 17:59:06 2012 +0100
@@ -28,7 +28,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 
-public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable {
+public final class FixedGuardNode extends FixedWithNextNode implements Simplifiable, Lowerable, LIRLowerable, Node.IterableNodeType {
 
     @Input private final NodeInputList<BooleanNode> conditions;
 
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java	Wed Mar 14 17:59:06 2012 +0100
@@ -115,7 +115,12 @@
     }
 
     public NodeIterable<PhiNode> phis() {
-        return this.usages().filter(PhiNode.class);
+        return this.usages().filter(new NodePredicate() {
+            @Override
+            public boolean apply(Node n) {
+                return n instanceof PhiNode && ((PhiNode) n).merge() == MergeNode.this;
+            }
+        }).filter(PhiNode.class);
     }
 
     @Override
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/ArrayLengthNode.java	Wed Mar 14 17:59:06 2012 +0100
@@ -41,7 +41,7 @@
     }
 
     public ArrayLengthNode(ValueNode array) {
-        super(StampFactory.intValue());
+        super(StampFactory.positiveInt());
         this.array = array;
     }
 
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/GraphTest.java	Wed Mar 14 17:59:06 2012 +0100
@@ -55,6 +55,7 @@
     protected final GraalRuntime runtime;
 
     public GraphTest() {
+        Debug.enable();
         this.runtime = GraalRuntimeAccess.getGraalRuntime();
     }
 
@@ -62,7 +63,7 @@
         if (expected.getNodeCount() != graph.getNodeCount()) {
             Debug.dump(expected, "Node count not matching - expected");
             Debug.dump(graph, "Node count not matching - actual");
-            Assert.fail("Graphs do not have the same number of nodes");
+            Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
         }
     }
 
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/ScalarTypeSystemTest.java	Wed Mar 14 17:59:06 2012 +0100
@@ -27,6 +27,7 @@
 import org.junit.*;
 
 import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.types.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.nodes.*;
 
@@ -43,7 +44,7 @@
         }
     }
 
-    @Test(expected = AssertionFailedError.class)
+    @Test
     public void test1() {
         test("test1Snippet", "referenceSnippet1");
     }
@@ -60,7 +61,7 @@
         }
     }
 
-    @Test(expected = AssertionFailedError.class)
+    @Test
     public void test2() {
         test("test2Snippet", "referenceSnippet1");
     }
@@ -77,7 +78,7 @@
         }
     }
 
-    @Test(expected = AssertionFailedError.class)
+    @Test
     public void test3() {
         test("test3Snippet", "referenceSnippet2");
     }
@@ -102,7 +103,7 @@
         }
     }
 
-    @Test(expected = AssertionFailedError.class)
+    @Test
     public void test4() {
         test("test4Snippet", "referenceSnippet2");
     }
@@ -119,7 +120,7 @@
         }
     }
 
-    @Test(expected = AssertionFailedError.class)
+    @Test
     public void test5() {
         test("test5Snippet", "referenceSnippet3");
     }
@@ -162,9 +163,12 @@
     }
 
     private void test(String snippet, String referenceSnippet) {
+
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
+        System.out.println("==================== " + snippet);
         new CanonicalizerPhase(null, runtime(), null).apply(graph);
+        new PropagateTypeCachePhase(null, null, null).apply(graph);
         StructuredGraph referenceGraph = parse(referenceSnippet);
         assertEquals(referenceGraph, graph);
     }
--- a/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java	Wed Mar 14 17:55:33 2012 +0100
+++ b/graal/com.oracle.graal.tests/src/com/oracle/graal/compiler/tests/TypeSystemTest.java	Wed Mar 14 17:59:06 2012 +0100
@@ -22,14 +22,21 @@
  */
 package com.oracle.graal.compiler.tests;
 
+import java.io.*;
+
+import junit.framework.Assert;
+
 import org.junit.*;
 
 import com.oracle.graal.compiler.phases.*;
+import com.oracle.graal.compiler.schedule.*;
 import com.oracle.graal.compiler.types.*;
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
+import com.oracle.graal.lir.cfg.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.printer.*;
 
 /**
  * In the following tests, the scalar type system of the compiler should be complete enough to see the relation between the different conditions.
@@ -60,12 +67,181 @@
         return 1;
     }
 
+    @Test
+    public void test3() {
+        test("test3Snippet", "referenceSnippet3");
+    }
+
+    public static int referenceSnippet3(Object o) {
+        if (o == null) {
+            return 1;
+        } else {
+            return 2;
+        }
+    }
+
+    @SuppressWarnings("unused")
+    public static int test3Snippet(Object o) {
+        if (o == null) {
+            if (o != null) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+    @Test
+    public void test4() {
+        test("test4Snippet", "referenceSnippet3");
+    }
+
+    public static final Object constantObject1 = "1";
+    public static final Object constantObject2 = "2";
+    public static final Object constantObject3 = "3";
+
+    public static int test4Snippet(Object o) {
+        if (o == null) {
+            if (o == constantObject1) {
+                return 3;
+            } else {
+                return 1;
+            }
+        } else {
+            return 2;
+        }
+    }
+
+//    @Test
+    public void test5() {
+        test("test5Snippet", "referenceSnippet5");
+    }
+
+    public static int referenceSnippet5(Object o, Object a) {
+        if (o == null) {
+            if (a == constantObject1 || a == constantObject2) {
+                return 1;
+            }
+        } else {
+            if (a == constantObject2 || a == constantObject3) {
+                if (a != null) {
+                    return 11;
+                }
+                return 2;
+            }
+        }
+        if (a == constantObject1) {
+            return 3;
+        }
+        return 5;
+    }
+
+    public static int test5Snippet(Object o, Object a) {
+        if (o == null) {
+            if (a == constantObject1 || a == constantObject2) {
+                if (a == null) {
+                    return 10;
+                }
+                return 1;
+            }
+        } else {
+            if (a == constantObject2 || a == constantObject3) {
+                if (a != null) {
+                    return 11;
+                }
+                return 2;
+            }
+        }
+        if (a == constantObject1) {
+            return 3;
+        }
+        if (a == constantObject2) {
+            return 4;
+        }
+        return 5;
+    }
+
+    @Test
+    public void test6() {
+        test("test6Snippet", CheckCastNode.class);
+    }
+
+    public static int test6Snippet(int i) throws IOException {
+        Object o = null;
+
+        if (i == 5) {
+            o = new FileInputStream("asdf");
+        }
+        if (i < 10) {
+            o = new ByteArrayInputStream(new byte[]{1, 2, 3});
+        }
+        if (i > 0) {
+            o = new BufferedInputStream(null);
+        }
+
+        return ((InputStream) o).available();
+    }
+
+    private void test(String snippet, String referenceSnippet) {
+
+        StructuredGraph graph = parse(snippet);
+        Debug.dump(graph, "Graph");
+        System.out.println("==================== " + snippet);
+        new CanonicalizerPhase(null, runtime(), null).apply(graph);
+        new PropagateTypeCachePhase(null, runtime(), null).apply(graph);
+        new CanonicalizerPhase(null, runtime(), null).apply(graph);
+        new GlobalValueNumberingPhase().apply(graph);
+        StructuredGraph referenceGraph = parse(referenceSnippet);
+        new CanonicalizerPhase(null, runtime(), null).apply(referenceGraph);
+        new GlobalValueNumberingPhase().apply(referenceGraph);
+        assertEquals(referenceGraph, graph);
+    }
+
+    @Override
+    protected void assertEquals(StructuredGraph expected, StructuredGraph graph) {
+        if (expected.getNodeCount() != graph.getNodeCount()) {
+            Debug.dump(expected, "Node count not matching - expected");
+            Debug.dump(graph, "Node count not matching - actual");
+            System.out.println("================ expected");
+            outputGraph(expected);
+            System.out.println("================ actual");
+            outputGraph(graph);
+            new IdealGraphPrinterDumpHandler().dump(graph, "asdf");
+            Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount());
+        }
+    }
+
+    public static void outputGraph(StructuredGraph graph) {
+        SchedulePhase schedule = new SchedulePhase();
+        schedule.apply(graph);
+        for (Block block : schedule.getCFG().getBlocks()) {
+            System.out.print("Block " + block + " ");
+            if (block == schedule.getCFG().getStartBlock()) {
+                System.out.print("* ");
+            }
+            System.out.print("-> ");
+            for (Block succ : block.getSuccessors()) {
+                System.out.print(succ + " ");
+            }
+            System.out.println();
+            for (Node node : schedule.getNodesFor().get(block)) {
+                System.out.println("  " + node + "    (" + node.usages().size() + ")");
+            }
+        }
+    }
+
+
     private <T extends Node & Node.IterableNodeType> void test(String snippet, Class<T> clazz) {
         StructuredGraph graph = parse(snippet);
         Debug.dump(graph, "Graph");
         new CanonicalizerPhase(null, runtime(), null).apply(graph);
-        new PropagateTypesPhase(null, null, null).apply(graph);
+        new PropagateTypeCachePhase(null, runtime(), null).apply(graph);
         Debug.dump(graph, "Graph");
+        if (graph.getNodes(clazz).iterator().hasNext()) {
+            outputGraph(graph);
+        }
         Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes(clazz).iterator().hasNext());
     }
 }