changeset 9238:8f01fe16e473

refactorings and cleanups for the removal of FixedNode.probability
author Christian Haeubl <haeubl@ssw.jku.at>
date Mon, 22 Apr 2013 17:49:13 +0200
parents 5fbee58dba33
children 6aea59f0965c
files graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/NodeProbabilities.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeInliningRelevanceClosure.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityClosure.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java
diffstat 17 files changed, 615 insertions(+), 624 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java	Mon Apr 22 17:49:13 2013 +0200
@@ -26,6 +26,7 @@
 import java.util.*;
 
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
 
 /**
  * Computes an ordering of the block that can be used by the linear scan register allocator and the
@@ -66,7 +67,7 @@
      * 
      * @return sorted list of blocks
      */
-    public static List<Block> computeLinearScanOrder(int blockCount, Block startBlock, NodeProbabilities nodeProbabilities) {
+    public static List<Block> computeLinearScanOrder(int blockCount, Block startBlock, NodesToDoubles nodeProbabilities) {
         List<Block> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
         PriorityQueue<Block> worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities);
@@ -80,7 +81,7 @@
      * 
      * @return sorted list of blocks
      */
-    public static List<Block> computeCodeEmittingOrder(int blockCount, Block startBlock, NodeProbabilities nodeProbabilities) {
+    public static List<Block> computeCodeEmittingOrder(int blockCount, Block startBlock, NodesToDoubles nodeProbabilities) {
         List<Block> order = new ArrayList<>();
         BitSet visitedBlocks = new BitSet(blockCount);
         PriorityQueue<Block> worklist = initializeWorklist(startBlock, visitedBlocks, nodeProbabilities);
@@ -92,7 +93,7 @@
     /**
      * Iteratively adds paths to the code emission block order.
      */
-    private static void computeCodeEmittingOrder(List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodeProbabilities nodeProbabilities) {
+    private static void computeCodeEmittingOrder(List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
         while (!worklist.isEmpty()) {
             Block nextImportantPath = worklist.poll();
             addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities);
@@ -102,7 +103,7 @@
     /**
      * Iteratively adds paths to the linear scan block order.
      */
-    private static void computeLinearScanOrder(List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodeProbabilities nodeProbabilities) {
+    private static void computeLinearScanOrder(List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
         while (!worklist.isEmpty()) {
             Block nextImportantPath = worklist.poll();
             addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, nodeProbabilities);
@@ -112,7 +113,7 @@
     /**
      * Initializes the priority queue used for the work list of blocks and adds the start block.
      */
-    private static PriorityQueue<Block> initializeWorklist(Block startBlock, BitSet visitedBlocks, NodeProbabilities nodeProbabilities) {
+    private static PriorityQueue<Block> initializeWorklist(Block startBlock, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
         PriorityQueue<Block> result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator(nodeProbabilities));
         result.add(startBlock);
         visitedBlocks.set(startBlock.getId());
@@ -122,7 +123,7 @@
     /**
      * Add a linear path to the linear scan order greedily following the most likely successor.
      */
-    private static void addPathToLinearScanOrder(Block block, List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodeProbabilities nodeProbabilities) {
+    private static void addPathToLinearScanOrder(Block block, List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
         block.setLinearScanNumber(order.size());
         order.add(block);
         Block mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, nodeProbabilities);
@@ -134,11 +135,11 @@
                 double unscheduledSum = 0.0;
                 for (Block pred : mostLikelySuccessor.getPredecessors()) {
                     if (pred.getLinearScanNumber() == -1) {
-                        unscheduledSum += nodeProbabilities.getProbability(pred.getBeginNode());
+                        unscheduledSum += nodeProbabilities.get(pred.getBeginNode());
                     }
                 }
 
-                if (unscheduledSum > nodeProbabilities.getProbability(block.getBeginNode()) / PENALTY_VERSUS_UNSCHEDULED) {
+                if (unscheduledSum > nodeProbabilities.get(block.getBeginNode()) / PENALTY_VERSUS_UNSCHEDULED) {
                     // Add this merge only after at least one additional predecessor gets scheduled.
                     visitedBlocks.clear(mostLikelySuccessor.getId());
                     return;
@@ -151,7 +152,7 @@
     /**
      * Add a linear path to the code emission order greedily following the most likely successor.
      */
-    private static void addPathToCodeEmittingOrder(Block block, List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodeProbabilities nodeProbabilities) {
+    private static void addPathToCodeEmittingOrder(Block block, List<Block> order, PriorityQueue<Block> worklist, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
 
         // Skip loop headers if there is only a single loop end block to make the backward jump be a
         // conditional jump.
@@ -198,12 +199,12 @@
     /**
      * Find the highest likely unvisited successor block of a given block.
      */
-    private static Block findAndMarkMostLikelySuccessor(Block block, BitSet visitedBlocks, NodeProbabilities nodeProbabilities) {
+    private static Block findAndMarkMostLikelySuccessor(Block block, BitSet visitedBlocks, NodesToDoubles nodeProbabilities) {
         Block result = null;
         for (Block successor : block.getSuccessors()) {
-            assert nodeProbabilities.getProbability(successor.getBeginNode()) >= 0.0 : "Probabilities must be positive";
+            assert nodeProbabilities.get(successor.getBeginNode()) >= 0.0 : "Probabilities must be positive";
             if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() &&
-                            (result == null || nodeProbabilities.getProbability(successor.getBeginNode()) >= nodeProbabilities.getProbability(result.getBeginNode()))) {
+                            (result == null || nodeProbabilities.get(successor.getBeginNode()) >= nodeProbabilities.get(result.getBeginNode()))) {
                 result = successor;
             }
         }
@@ -246,9 +247,9 @@
      */
     private static class BlockOrderComparator implements Comparator<Block> {
 
-        private final NodeProbabilities probabilities;
+        private final NodesToDoubles probabilities;
 
-        public BlockOrderComparator(NodeProbabilities probabilities) {
+        public BlockOrderComparator(NodesToDoubles probabilities) {
             this.probabilities = probabilities;
         }
 
@@ -261,7 +262,7 @@
             }
 
             // Blocks with high probability before blocks with low probability.
-            if (probabilities.getProbability(a.getBeginNode()) > probabilities.getProbability(b.getBeginNode())) {
+            if (probabilities.get(a.getBeginNode()) > probabilities.get(b.getBeginNode())) {
                 return -1;
             } else {
                 return 1;
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java	Mon Apr 22 17:49:13 2013 +0200
@@ -33,10 +33,11 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.nodes.*;
 import com.oracle.graal.virtual.phases.ea.*;
@@ -133,11 +134,11 @@
             Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", result.getNodes(NewInstanceNode.class).isEmpty());
             Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", result.getNodes(NewArrayNode.class).isEmpty());
 
-            NodeProbabilities nodeProbabilities = new ComputeProbabilityClosure(result).run();
+            NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(result).apply();
             double probabilitySum = 0;
             int materializeCount = 0;
             for (MaterializeObjectNode materialize : result.getNodes(MaterializeObjectNode.class)) {
-                probabilitySum += nodeProbabilities.getProbability(materialize);
+                probabilitySum += nodeProbabilities.get(materialize);
                 materializeCount++;
             }
             Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Mon Apr 22 17:49:13 2013 +0200
@@ -38,9 +38,11 @@
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.phases.tiers.*;
 import com.oracle.graal.virtual.phases.ea.*;
@@ -170,7 +172,7 @@
 
             @Override
             public LIR call() {
-                NodeProbabilities nodeProbabilities = new ComputeProbabilityClosure(graph).run();
+                NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
                 List<Block> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, nodeProbabilities);
                 List<Block> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, nodeProbabilities);
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java	Mon Apr 22 17:49:13 2013 +0200
@@ -26,6 +26,7 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 
 public abstract class LoopPolicies {
@@ -35,9 +36,9 @@
     }
 
     // TODO (gd) change when inversion is available
-    public static boolean shouldPeel(LoopEx loop, NodeProbabilities probabilities) {
+    public static boolean shouldPeel(LoopEx loop, NodesToDoubles probabilities) {
         LoopBeginNode loopBegin = loop.loopBegin();
-        double entryProbability = probabilities.getProbability(loopBegin.forwardEnd());
+        double entryProbability = probabilities.get(loopBegin.forwardEnd());
         return entryProbability > GraalOptions.MinimumPeelProbability && loop.size() + loopBegin.graph().getNodeCount() < GraalOptions.MaximumDesiredSize;
     }
 
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java	Mon Apr 22 17:49:13 2013 +0200
@@ -25,9 +25,9 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.loop.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.graph.*;
 
 public class LoopTransformHighPhase extends Phase {
 
@@ -35,7 +35,7 @@
     protected void run(StructuredGraph graph) {
         if (graph.hasLoops()) {
             if (GraalOptions.LoopPeeling) {
-                NodeProbabilities probabilities = new ComputeProbabilityClosure(graph).run();
+                NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
                 LoopsData data = new LoopsData(graph);
                 for (LoopEx loop : data.outterFirst()) {
                     if (LoopPolicies.shouldPeel(loop, probabilities)) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/NodeProbabilities.java	Mon Apr 22 17:06:06 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.nodes.cfg;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.*;
-
-public class NodeProbabilities {
-
-    private final IdentityHashMap<FixedNode, Double> nodeProbabilities;
-
-    public NodeProbabilities(int numberOfNodes) {
-        this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes);
-    }
-
-    public void setProbability(FixedNode n, double value) {
-        nodeProbabilities.put(n, value);
-    }
-
-    public double getProbability(FixedNode n) {
-        Double value = nodeProbabilities.get(n);
-        assert value != null;
-        return value;
-    }
-
-    public int size() {
-        return nodeProbabilities.size();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java	Mon Apr 22 17:49:13 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.nodes.util;
+
+import java.util.*;
+
+import com.oracle.graal.nodes.*;
+
+public class NodesToDoubles {
+
+    private final IdentityHashMap<FixedNode, Double> nodeProbabilities;
+
+    public NodesToDoubles(int numberOfNodes) {
+        this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes);
+    }
+
+    public void put(FixedNode n, double value) {
+        nodeProbabilities.put(n, value);
+    }
+
+    public double get(FixedNode n) {
+        Double value = nodeProbabilities.get(n);
+        assert value != null;
+        return value;
+    }
+}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeInliningRelevanceClosure.java	Mon Apr 22 17:06:06 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,223 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.graal.phases.common;
-
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.phases.graph.*;
-
-public class ComputeInliningRelevanceClosure {
-
-    private static final double EPSILON = 1d / Integer.MAX_VALUE;
-
-    private final StructuredGraph graph;
-    private final NodeProbabilities nodeProbabilities;
-    private final NodeProbabilities nodeRelevances;
-
-    public ComputeInliningRelevanceClosure(StructuredGraph graph, NodeProbabilities nodeProbabilities) {
-        this.graph = graph;
-        this.nodeProbabilities = nodeProbabilities;
-        this.nodeRelevances = new NodeProbabilities(graph.getNodeCount());
-    }
-
-    public NodeProbabilities run() {
-        new ComputeInliningRelevanceIterator(graph).apply();
-        return nodeRelevances;
-    }
-
-    private class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator {
-
-        private final HashMap<FixedNode, Scope> scopes;
-        private double currentProbability;
-        private double parentRelevance;
-
-        public ComputeInliningRelevanceIterator(StructuredGraph graph) {
-            super(graph);
-            this.scopes = computeLowestPathProbabilities();
-        }
-
-        @Override
-        protected void initializeScope() {
-            Scope scope = scopes.get(currentScopeStart);
-            parentRelevance = getParentScopeRelevance(scope);
-            currentProbability = scope.minPathProbability;
-        }
-
-        private double getParentScopeRelevance(Scope scope) {
-            if (scope.start instanceof LoopBeginNode) {
-                assert scope.parent != null;
-                double parentProbability = 0;
-                for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
-                    parentProbability += nodeProbabilities.getProbability(end);
-                }
-                return parentProbability / scope.parent.minPathProbability;
-            } else {
-                assert scope.parent == null;
-                return 1.0;
-            }
-        }
-
-        @Override
-        protected void invoke(Invoke invoke) {
-            double probability = nodeProbabilities.getProbability(invoke.asNode());
-            assert !Double.isNaN(probability);
-
-            double relevance = (probability / currentProbability) * Math.min(1.0, parentRelevance);
-            nodeRelevances.setProbability(invoke.asNode(), relevance);
-            assert !Double.isNaN(relevance);
-        }
-
-        private HashMap<FixedNode, Scope> computeLowestPathProbabilities() {
-            HashMap<FixedNode, Scope> result = new HashMap<>();
-
-            for (Scope scope : computeScopes()) {
-                double lowestPathProbability = computeLowestPathProbability(scope);
-                scope.minPathProbability = Math.max(EPSILON, lowestPathProbability);
-                result.put(scope.start, scope);
-            }
-
-            return result;
-        }
-
-        private Scope[] computeScopes() {
-            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
-
-            Loop[] loops = cfg.getLoops();
-            HashMap<Loop, Scope> processedScopes = new HashMap<>();
-            Scope[] result = new Scope[loops.length + 1];
-            Scope methodScope = new Scope(graph.start(), null);
-            processedScopes.put(null, methodScope);
-
-            result[0] = methodScope;
-            for (int i = 0; i < loops.length; i++) {
-                result[i + 1] = createScope(loops[i], processedScopes);
-            }
-
-            return result;
-        }
-
-        private Scope createScope(Loop loop, HashMap<Loop, Scope> processedLoops) {
-            Scope parent = processedLoops.get(loop.parent);
-            if (parent == null) {
-                parent = createScope(loop.parent, processedLoops);
-            }
-            Scope result = new Scope(loop.loopBegin(), parent);
-            processedLoops.put(loop, result);
-            return result;
-        }
-
-        private double computeLowestPathProbability(Scope scope) {
-            FixedNode scopeStart = scope.start;
-            ArrayList<FixedNode> pathBeginNodes = new ArrayList<>();
-            pathBeginNodes.add(scopeStart);
-            double minPathProbability = nodeProbabilities.getProbability(scopeStart);
-            boolean isLoopScope = scopeStart instanceof LoopBeginNode;
-
-            do {
-                Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
-                do {
-                    if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
-                        return minPathProbability;
-                    } else if (current instanceof LoopBeginNode && current != scopeStart) {
-                        current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
-                        minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
-                    } else if (current instanceof ControlSplitNode) {
-                        current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
-                        minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
-                    } else {
-                        assert current.successors().count() <= 1;
-                        current = current.successors().first();
-                    }
-                } while (current != null);
-            } while (!pathBeginNodes.isEmpty());
-
-            return minPathProbability;
-        }
-
-        private double getMinPathProbability(FixedNode current, double minPathProbability) {
-            if (current != null && nodeProbabilities.getProbability(current) < minPathProbability) {
-                return nodeProbabilities.getProbability(current);
-            }
-            return minPathProbability;
-        }
-
-        private Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList<FixedNode> pathBeginNodes) {
-            Node maxSux = null;
-            double maxProbability = 0.0;
-            int pathBeginCount = pathBeginNodes.size();
-
-            for (Node sux : controlSplit.successors()) {
-                double probability = controlSplit.probability((BeginNode) sux);
-                if (probability > maxProbability) {
-                    maxProbability = probability;
-                    maxSux = sux;
-                    truncate(pathBeginNodes, pathBeginCount);
-                } else if (probability == maxProbability) {
-                    pathBeginNodes.add((FixedNode) sux);
-                }
-            }
-
-            return maxSux;
-        }
-
-        private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList<FixedNode> pathBeginNodes) {
-            Node maxSux = null;
-            double maxProbability = 0.0;
-            int pathBeginCount = pathBeginNodes.size();
-
-            for (LoopExitNode sux : loopBegin.loopExits()) {
-                double probability = nodeProbabilities.getProbability(sux);
-                if (probability > maxProbability) {
-                    maxProbability = probability;
-                    maxSux = sux;
-                    truncate(pathBeginNodes, pathBeginCount);
-                } else if (probability == maxProbability) {
-                    pathBeginNodes.add(sux);
-                }
-            }
-
-            return maxSux;
-        }
-
-        private void truncate(ArrayList<FixedNode> pathBeginNodes, int pathBeginCount) {
-            for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
-                pathBeginNodes.remove(pathBeginNodes.size() - 1);
-            }
-        }
-    }
-
-    private static class Scope {
-
-        public final FixedNode start;
-        public final Scope parent;
-        public double minPathProbability;
-
-        public Scope(FixedNode start, Scope parent) {
-            this.start = start;
-            this.parent = parent;
-        }
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ComputeProbabilityClosure.java	Mon Apr 22 17:06:06 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,296 +0,0 @@
-/*
- * 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.phases.common;
-
-import java.util.*;
-
-import com.oracle.graal.debug.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.phases.graph.*;
-
-/**
- * Computes probabilities for nodes in a graph.
- * <p>
- * The computation of absolute probabilities works in three steps:
- * <ol>
- * <li>{@link PropagateProbability} traverses the graph in post order (merges after their ends, ...)
- * and keeps track of the "probability state". Whenever it encounters a {@link ControlSplitNode} it
- * uses the split's probability information to divide the probability upon the successors. Whenever
- * it encounters an {@link Invoke} it assumes that the exception edge is unlikely and propagates the
- * whole probability to the normal successor. Whenever it encounters a {@link MergeNode} it sums up
- * the probability of all predecessors. It also maintains a set of active loops (whose
- * {@link LoopBeginNode} has been visited) and builds def/use information for step 2.</li>
- * <li></li>
- * <li>{@link PropagateLoopFrequency} propagates the loop frequencies and multiplies each
- * {@link FixedNode}'s probability with its loop frequency.</li>
- * </ol>
- * TODO: add exception probability information to Invokes
- */
-public class ComputeProbabilityClosure {
-
-    private static final double EPSILON = 1d / Integer.MAX_VALUE;
-
-    private final StructuredGraph graph;
-    private final NodeProbabilities nodeProbabilities;
-    private final Set<LoopInfo> loopInfos;
-    private final Map<MergeNode, Set<LoopInfo>> mergeLoops;
-
-    public ComputeProbabilityClosure(StructuredGraph graph) {
-        this.graph = graph;
-        this.nodeProbabilities = new NodeProbabilities(graph.getNodeCount());
-        this.loopInfos = new HashSet<>();
-        this.mergeLoops = new IdentityHashMap<>();
-    }
-
-    public NodeProbabilities run() {
-        new PropagateProbability(graph.start()).apply();
-        Debug.dump(graph, "After PropagateProbability");
-        computeLoopFactors();
-        Debug.dump(graph, "After computeLoopFactors");
-        new PropagateLoopFrequency(graph.start()).apply();
-        return nodeProbabilities;
-    }
-
-    private void computeLoopFactors() {
-        for (LoopInfo info : loopInfos) {
-            double frequency = info.loopFrequency(nodeProbabilities);
-            assert frequency != -1;
-        }
-    }
-
-    private static boolean isRelativeProbability(double prob) {
-        // 1.01 to allow for some rounding errors
-        return prob >= 0 && prob <= 1.01;
-    }
-
-    public static class LoopInfo {
-
-        public final LoopBeginNode loopBegin;
-
-        public final NodeMap<Set<LoopInfo>> requires;
-
-        private double loopFrequency = -1;
-        public boolean ended = false;
-
-        public LoopInfo(LoopBeginNode loopBegin) {
-            this.loopBegin = loopBegin;
-            this.requires = loopBegin.graph().createNodeMap();
-        }
-
-        public double loopFrequency(NodeProbabilities nodeProbabilities) {
-            if (loopFrequency == -1 && ended) {
-                double backEdgeProb = 0.0;
-                for (LoopEndNode le : loopBegin.loopEnds()) {
-                    double factor = 1;
-                    Set<LoopInfo> requireds = requires.get(le);
-                    for (LoopInfo required : requireds) {
-                        double t = required.loopFrequency(nodeProbabilities);
-                        if (t == -1) {
-                            return -1;
-                        }
-                        factor *= t;
-                    }
-                    backEdgeProb += nodeProbabilities.getProbability(le) * factor;
-                }
-                double d = nodeProbabilities.getProbability(loopBegin) - backEdgeProb;
-                if (d < EPSILON) {
-                    d = EPSILON;
-                }
-                loopFrequency = nodeProbabilities.getProbability(loopBegin) / d;
-                loopBegin.setLoopFrequency(loopFrequency);
-            }
-            return loopFrequency;
-        }
-    }
-
-    private class Probability implements MergeableState<Probability> {
-
-        public double probability;
-        public HashSet<LoopInfo> loops;
-        public LoopInfo loopInfo;
-
-        public Probability(double probability, HashSet<LoopInfo> loops) {
-            this.probability = probability;
-            this.loops = new HashSet<>(4);
-            if (loops != null) {
-                this.loops.addAll(loops);
-            }
-        }
-
-        @Override
-        public Probability clone() {
-            return new Probability(probability, loops);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<Probability> withStates) {
-            if (merge.forwardEndCount() > 1) {
-                HashSet<LoopInfo> intersection = new HashSet<>(loops);
-                for (Probability other : withStates) {
-                    intersection.retainAll(other.loops);
-                }
-                for (LoopInfo info : loops) {
-                    if (!intersection.contains(info)) {
-                        double loopFrequency = info.loopFrequency(nodeProbabilities);
-                        if (loopFrequency == -1) {
-                            return false;
-                        }
-                        probability *= loopFrequency;
-                    }
-                }
-                for (Probability other : withStates) {
-                    double prob = other.probability;
-                    for (LoopInfo info : other.loops) {
-                        if (!intersection.contains(info)) {
-                            double loopFrequency = info.loopFrequency(nodeProbabilities);
-                            if (loopFrequency == -1) {
-                                return false;
-                            }
-                            prob *= loopFrequency;
-                        }
-                    }
-                    probability += prob;
-                }
-                loops = intersection;
-                mergeLoops.put(merge, new HashSet<>(intersection));
-                assert isRelativeProbability(probability) : probability;
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            loopInfo = new LoopInfo(loopBegin);
-            loopInfos.add(loopInfo);
-            loops.add(loopInfo);
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<Probability> loopEndStates) {
-            assert loopInfo != null;
-            List<LoopEndNode> loopEnds = loopBegin.orderedLoopEnds();
-            int i = 0;
-            for (Probability proba : loopEndStates) {
-                LoopEndNode loopEnd = loopEnds.get(i++);
-                Set<LoopInfo> requires = loopInfo.requires.get(loopEnd);
-                if (requires == null) {
-                    requires = new HashSet<>();
-                    loopInfo.requires.set(loopEnd, requires);
-                }
-                for (LoopInfo innerLoop : proba.loops) {
-                    if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) {
-                        requires.add(innerLoop);
-                    }
-                }
-            }
-            loopInfo.ended = true;
-        }
-
-        @Override
-        public void afterSplit(BeginNode node) {
-            assert node.predecessor() != null;
-            Node pred = node.predecessor();
-            if (pred instanceof Invoke) {
-                Invoke x = (Invoke) pred;
-                if (x.next() != node) {
-                    probability = 0;
-                }
-            } else {
-                assert pred instanceof ControlSplitNode;
-                ControlSplitNode x = (ControlSplitNode) pred;
-                probability *= x.probability(node);
-            }
-        }
-    }
-
-    private class PropagateProbability extends PostOrderNodeIterator<Probability> {
-
-        public PropagateProbability(FixedNode start) {
-            super(start, new Probability(1d, null));
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            nodeProbabilities.setProbability(node, state.probability);
-        }
-    }
-
-    private class LoopCount implements MergeableState<LoopCount> {
-
-        public double count;
-
-        public LoopCount(double count) {
-            this.count = count;
-        }
-
-        @Override
-        public LoopCount clone() {
-            return new LoopCount(count);
-        }
-
-        @Override
-        public boolean merge(MergeNode merge, List<LoopCount> withStates) {
-            assert merge.forwardEndCount() == withStates.size() + 1;
-            if (merge.forwardEndCount() > 1) {
-                Set<LoopInfo> loops = mergeLoops.get(merge);
-                assert loops != null;
-                double countProd = 1;
-                for (LoopInfo loop : loops) {
-                    countProd *= loop.loopFrequency(nodeProbabilities);
-                }
-                count = countProd;
-            }
-            return true;
-        }
-
-        @Override
-        public void loopBegin(LoopBeginNode loopBegin) {
-            count *= loopBegin.loopFrequency();
-        }
-
-        @Override
-        public void loopEnds(LoopBeginNode loopBegin, List<LoopCount> loopEndStates) {
-            // nothing to do...
-        }
-
-        @Override
-        public void afterSplit(BeginNode node) {
-            // nothing to do...
-        }
-    }
-
-    private class PropagateLoopFrequency extends PostOrderNodeIterator<LoopCount> {
-
-        public PropagateLoopFrequency(FixedNode start) {
-            super(start, new LoopCount(1d));
-        }
-
-        @Override
-        protected void node(FixedNode node) {
-            nodeProbabilities.setProbability(node, nodeProbabilities.getProbability(node) * state.count);
-        }
-
-    }
-}
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Mon Apr 22 17:49:13 2013 +0200
@@ -31,15 +31,16 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.PhasePlan.PhasePosition;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
 import com.oracle.graal.phases.common.InliningUtil.InlineInfo;
 import com.oracle.graal.phases.common.InliningUtil.InliningCallback;
 import com.oracle.graal.phases.common.InliningUtil.InliningPolicy;
+import com.oracle.graal.phases.graph.*;
 
 public class InliningPhase extends Phase implements InliningCallback {
 
@@ -100,8 +101,8 @@
 
     @Override
     protected void run(final StructuredGraph graph) {
-        NodeProbabilities nodeProbabilities = new ComputeProbabilityClosure(graph).run();
-        NodeProbabilities nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).run();
+        NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+        NodesToDoubles nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).apply();
         inliningPolicy.initialize(graph);
 
         while (inliningPolicy.continueInlining(graph)) {
@@ -124,8 +125,8 @@
                             new CanonicalizerPhase.Instance(runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph);
                         }
 
-                        nodeProbabilities = new ComputeProbabilityClosure(graph).run();
-                        nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).run();
+                        nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+                        nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).apply();
 
                         inliningCount++;
                         metricInliningPerformed.increment();
@@ -164,9 +165,8 @@
                 }
                 assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
 
-                if (GraalOptions.ProbabilityAnalysis) {
-                    new DeadCodeEliminationPhase().apply(newGraph);
-                }
+                new DeadCodeEliminationPhase().apply(newGraph);
+
                 if (GraalOptions.OptCanonicalizer) {
                     new CanonicalizerPhase.Instance(runtime, assumptions).apply(newGraph);
                 }
@@ -183,7 +183,7 @@
 
     private interface InliningDecision {
 
-        boolean isWorthInlining(InlineInfo info, NodeProbabilities nodeProbabilities, NodeProbabilities nodeRelevance);
+        boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance);
     }
 
     private static class GreedySizeBasedInliningDecision implements InliningDecision {
@@ -199,8 +199,7 @@
         }
 
         @Override
-        public boolean isWorthInlining(InlineInfo info, NodeProbabilities nodeProbabilities, NodeProbabilities nodeRelevance) {
-            assert GraalOptions.ProbabilityAnalysis;
+        public boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance) {
             /*
              * TODO (chaeubl): invoked methods that are on important paths but not yet compiled ->
              * will be compiled anyways and it is likely that we are the only caller... might be
@@ -226,7 +225,7 @@
             int bytecodeSize = (int) (bytecodeCodeSize(info) / bonus);
             int complexity = (int) (compilationComplexity(info) / bonus);
             int compiledCodeSize = (int) (compiledCodeSize(info) / bonus);
-            double relevance = nodeRelevance.getProbability(info.invoke().asNode());
+            double relevance = nodeRelevance.get(info.invoke().asNode());
             /*
              * as long as the compiled code size is small enough (or the method was not yet
              * compiled), we can do a pretty general inlining that suits most situations
@@ -245,7 +244,7 @@
              * the normal inlining did not fit this invoke, so check if we have any reason why we
              * should still do the inlining
              */
-            double probability = nodeProbabilities.getProbability(info.invoke().asNode());
+            double probability = nodeProbabilities.get(info.invoke().asNode());
             int transferredValues = numberOfTransferredValues(info);
             int invokeUsages = countInvokeUsages(info);
             int moreSpecificArguments = countMoreSpecificArgumentInfo(info);
@@ -415,7 +414,7 @@
         }
 
         @Override
-        public boolean isWorthInlining(InlineInfo info, NodeProbabilities nodeProbabilities, NodeProbabilities nodeRelevance) {
+        public boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance) {
             return inliningDecision.isWorthInlining(info, nodeProbabilities, nodeRelevance);
         }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Mon Apr 22 17:49:13 2013 +0200
@@ -35,7 +35,6 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
@@ -71,7 +70,7 @@
 
         void scanInvokes(Iterable<? extends Node> newNodes);
 
-        boolean isWorthInlining(InlineInfo info, NodeProbabilities nodeProbabilities, NodeProbabilities nodeRelevance);
+        boolean isWorthInlining(InlineInfo info, NodesToDoubles nodeProbabilities, NodesToDoubles nodeRelevance);
     }
 
     /**
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Mon Apr 22 17:49:13 2013 +0200
@@ -29,13 +29,13 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.VirtualState.NodeClosure;
-import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.extended.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.graph.*;
 
 /**
  * This class is a phase that looks for opportunities for tail duplication. The static method
@@ -130,12 +130,12 @@
 
     @Override
     protected void run(StructuredGraph graph) {
-        NodeProbabilities nodeProbabilities = new ComputeProbabilityClosure(graph).run();
+        NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
 
         // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
         // duplication.
         for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
-            if (!(merge instanceof LoopBeginNode) && nodeProbabilities.getProbability(merge) >= GraalOptions.TailDuplicationProbability) {
+            if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= GraalOptions.TailDuplicationProbability) {
                 tailDuplicate(merge, DEFAULT_DECISION, null);
             }
         }
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Mon Apr 22 17:49:13 2013 +0200
@@ -73,9 +73,6 @@
     public static double  TailDuplicationProbability         = 0.5;
     public static int     TailDuplicationTrivialSize         = 1;
 
-    // absolute probability analysis
-    public static boolean ProbabilityAnalysis                = true;
-
     // profiling information
     public static int     DeoptsToDisableOptimisticOptimization = 40;
     public static int     MatureExecutionsBranch             = 1;
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/OptimisticOptimizations.java	Mon Apr 22 17:49:13 2013 +0200
@@ -53,10 +53,6 @@
         if (checkDeoptimizations(method.getProfilingInfo(), deoptReason)) {
             enabledOpts.add(optimization);
         } else {
-            /*
-             * TODO (chaeubl): see GRAAL-75 (remove when we are sure that optimistic optimizations
-             * are not disabled unnecessarily
-             */
             disabledOptimisticOptsMetric.increment();
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java	Mon Apr 22 17:49:13 2013 +0200
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.phases.graph;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.nodes.util.*;
+
+public class ComputeInliningRelevanceClosure {
+
+    private static final double EPSILON = 1d / Integer.MAX_VALUE;
+
+    private final StructuredGraph graph;
+    private final NodesToDoubles nodeProbabilities;
+    private final NodesToDoubles nodeRelevances;
+
+    public ComputeInliningRelevanceClosure(StructuredGraph graph, NodesToDoubles nodeProbabilities) {
+        this.graph = graph;
+        this.nodeProbabilities = nodeProbabilities;
+        this.nodeRelevances = new NodesToDoubles(graph.getNodeCount());
+    }
+
+    public NodesToDoubles apply() {
+        new ComputeInliningRelevanceIterator(graph).apply();
+        return nodeRelevances;
+    }
+
+    private class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator {
+
+        private final HashMap<FixedNode, Scope> scopes;
+        private double currentProbability;
+        private double parentRelevance;
+
+        public ComputeInliningRelevanceIterator(StructuredGraph graph) {
+            super(graph);
+            this.scopes = computeLowestPathProbabilities();
+        }
+
+        @Override
+        protected void initializeScope() {
+            Scope scope = scopes.get(currentScopeStart);
+            parentRelevance = getParentScopeRelevance(scope);
+            currentProbability = scope.minPathProbability;
+        }
+
+        private double getParentScopeRelevance(Scope scope) {
+            if (scope.start instanceof LoopBeginNode) {
+                assert scope.parent != null;
+                double parentProbability = 0;
+                for (EndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
+                    parentProbability += nodeProbabilities.get(end);
+                }
+                return parentProbability / scope.parent.minPathProbability;
+            } else {
+                assert scope.parent == null;
+                return 1.0;
+            }
+        }
+
+        @Override
+        protected void invoke(Invoke invoke) {
+            double probability = nodeProbabilities.get(invoke.asNode());
+            assert !Double.isNaN(probability);
+
+            double relevance = (probability / currentProbability) * Math.min(1.0, parentRelevance);
+            nodeRelevances.put(invoke.asNode(), relevance);
+            assert !Double.isNaN(relevance);
+        }
+
+        private HashMap<FixedNode, Scope> computeLowestPathProbabilities() {
+            HashMap<FixedNode, Scope> result = new HashMap<>();
+
+            for (Scope scope : computeScopes()) {
+                double lowestPathProbability = computeLowestPathProbability(scope);
+                scope.minPathProbability = Math.max(EPSILON, lowestPathProbability);
+                result.put(scope.start, scope);
+            }
+
+            return result;
+        }
+
+        private Scope[] computeScopes() {
+            ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
+
+            Loop[] loops = cfg.getLoops();
+            HashMap<Loop, Scope> processedScopes = new HashMap<>();
+            Scope[] result = new Scope[loops.length + 1];
+            Scope methodScope = new Scope(graph.start(), null);
+            processedScopes.put(null, methodScope);
+
+            result[0] = methodScope;
+            for (int i = 0; i < loops.length; i++) {
+                result[i + 1] = createScope(loops[i], processedScopes);
+            }
+
+            return result;
+        }
+
+        private Scope createScope(Loop loop, HashMap<Loop, Scope> processedLoops) {
+            Scope parent = processedLoops.get(loop.parent);
+            if (parent == null) {
+                parent = createScope(loop.parent, processedLoops);
+            }
+            Scope result = new Scope(loop.loopBegin(), parent);
+            processedLoops.put(loop, result);
+            return result;
+        }
+
+        private double computeLowestPathProbability(Scope scope) {
+            FixedNode scopeStart = scope.start;
+            ArrayList<FixedNode> pathBeginNodes = new ArrayList<>();
+            pathBeginNodes.add(scopeStart);
+            double minPathProbability = nodeProbabilities.get(scopeStart);
+            boolean isLoopScope = scopeStart instanceof LoopBeginNode;
+
+            do {
+                Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
+                do {
+                    if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
+                        return minPathProbability;
+                    } else if (current instanceof LoopBeginNode && current != scopeStart) {
+                        current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
+                        minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+                    } else if (current instanceof ControlSplitNode) {
+                        current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
+                        minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+                    } else {
+                        assert current.successors().count() <= 1;
+                        current = current.successors().first();
+                    }
+                } while (current != null);
+            } while (!pathBeginNodes.isEmpty());
+
+            return minPathProbability;
+        }
+
+        private double getMinPathProbability(FixedNode current, double minPathProbability) {
+            if (current != null && nodeProbabilities.get(current) < minPathProbability) {
+                return nodeProbabilities.get(current);
+            }
+            return minPathProbability;
+        }
+
+        private Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList<FixedNode> pathBeginNodes) {
+            Node maxSux = null;
+            double maxProbability = 0.0;
+            int pathBeginCount = pathBeginNodes.size();
+
+            for (Node sux : controlSplit.successors()) {
+                double probability = controlSplit.probability((BeginNode) sux);
+                if (probability > maxProbability) {
+                    maxProbability = probability;
+                    maxSux = sux;
+                    truncate(pathBeginNodes, pathBeginCount);
+                } else if (probability == maxProbability) {
+                    pathBeginNodes.add((FixedNode) sux);
+                }
+            }
+
+            return maxSux;
+        }
+
+        private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList<FixedNode> pathBeginNodes) {
+            Node maxSux = null;
+            double maxProbability = 0.0;
+            int pathBeginCount = pathBeginNodes.size();
+
+            for (LoopExitNode sux : loopBegin.loopExits()) {
+                double probability = nodeProbabilities.get(sux);
+                if (probability > maxProbability) {
+                    maxProbability = probability;
+                    maxSux = sux;
+                    truncate(pathBeginNodes, pathBeginCount);
+                } else if (probability == maxProbability) {
+                    pathBeginNodes.add(sux);
+                }
+            }
+
+            return maxSux;
+        }
+
+        private void truncate(ArrayList<FixedNode> pathBeginNodes, int pathBeginCount) {
+            for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
+                pathBeginNodes.remove(pathBeginNodes.size() - 1);
+            }
+        }
+    }
+
+    private static class Scope {
+
+        public final FixedNode start;
+        public final Scope parent;
+        public double minPathProbability;
+
+        public Scope(FixedNode start, Scope parent) {
+            this.start = start;
+            this.parent = parent;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java	Mon Apr 22 17:49:13 2013 +0200
@@ -0,0 +1,295 @@
+/*
+ * 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.phases.graph;
+
+import java.util.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.util.*;
+
+/**
+ * Computes probabilities for nodes in a graph.
+ * <p>
+ * The computation of absolute probabilities works in three steps:
+ * <ol>
+ * <li>{@link PropagateProbability} traverses the graph in post order (merges after their ends, ...)
+ * and keeps track of the "probability state". Whenever it encounters a {@link ControlSplitNode} it
+ * uses the split's probability information to divide the probability upon the successors. Whenever
+ * it encounters an {@link Invoke} it assumes that the exception edge is unlikely and propagates the
+ * whole probability to the normal successor. Whenever it encounters a {@link MergeNode} it sums up
+ * the probability of all predecessors. It also maintains a set of active loops (whose
+ * {@link LoopBeginNode} has been visited) and builds def/use information for step 2.</li>
+ * <li></li>
+ * <li>{@link PropagateLoopFrequency} propagates the loop frequencies and multiplies each
+ * {@link FixedNode}'s probability with its loop frequency.</li>
+ * </ol>
+ * TODO: add exception probability information to Invokes
+ */
+public class ComputeProbabilityClosure {
+
+    private static final double EPSILON = 1d / Integer.MAX_VALUE;
+
+    private final StructuredGraph graph;
+    private final NodesToDoubles nodeProbabilities;
+    private final Set<LoopInfo> loopInfos;
+    private final Map<MergeNode, Set<LoopInfo>> mergeLoops;
+
+    public ComputeProbabilityClosure(StructuredGraph graph) {
+        this.graph = graph;
+        this.nodeProbabilities = new NodesToDoubles(graph.getNodeCount());
+        this.loopInfos = new HashSet<>();
+        this.mergeLoops = new IdentityHashMap<>();
+    }
+
+    public NodesToDoubles apply() {
+        new PropagateProbability(graph.start()).apply();
+        Debug.dump(graph, "After PropagateProbability");
+        computeLoopFactors();
+        Debug.dump(graph, "After computeLoopFactors");
+        new PropagateLoopFrequency(graph.start()).apply();
+        return nodeProbabilities;
+    }
+
+    private void computeLoopFactors() {
+        for (LoopInfo info : loopInfos) {
+            double frequency = info.loopFrequency(nodeProbabilities);
+            assert frequency != -1;
+        }
+    }
+
+    private static boolean isRelativeProbability(double prob) {
+        // 1.01 to allow for some rounding errors
+        return prob >= 0 && prob <= 1.01;
+    }
+
+    public static class LoopInfo {
+
+        public final LoopBeginNode loopBegin;
+
+        public final NodeMap<Set<LoopInfo>> requires;
+
+        private double loopFrequency = -1;
+        public boolean ended = false;
+
+        public LoopInfo(LoopBeginNode loopBegin) {
+            this.loopBegin = loopBegin;
+            this.requires = loopBegin.graph().createNodeMap();
+        }
+
+        public double loopFrequency(NodesToDoubles nodeProbabilities) {
+            if (loopFrequency == -1 && ended) {
+                double backEdgeProb = 0.0;
+                for (LoopEndNode le : loopBegin.loopEnds()) {
+                    double factor = 1;
+                    Set<LoopInfo> requireds = requires.get(le);
+                    for (LoopInfo required : requireds) {
+                        double t = required.loopFrequency(nodeProbabilities);
+                        if (t == -1) {
+                            return -1;
+                        }
+                        factor *= t;
+                    }
+                    backEdgeProb += nodeProbabilities.get(le) * factor;
+                }
+                double d = nodeProbabilities.get(loopBegin) - backEdgeProb;
+                if (d < EPSILON) {
+                    d = EPSILON;
+                }
+                loopFrequency = nodeProbabilities.get(loopBegin) / d;
+                loopBegin.setLoopFrequency(loopFrequency);
+            }
+            return loopFrequency;
+        }
+    }
+
+    private class Probability implements MergeableState<Probability> {
+
+        public double probability;
+        public HashSet<LoopInfo> loops;
+        public LoopInfo loopInfo;
+
+        public Probability(double probability, HashSet<LoopInfo> loops) {
+            this.probability = probability;
+            this.loops = new HashSet<>(4);
+            if (loops != null) {
+                this.loops.addAll(loops);
+            }
+        }
+
+        @Override
+        public Probability clone() {
+            return new Probability(probability, loops);
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<Probability> withStates) {
+            if (merge.forwardEndCount() > 1) {
+                HashSet<LoopInfo> intersection = new HashSet<>(loops);
+                for (Probability other : withStates) {
+                    intersection.retainAll(other.loops);
+                }
+                for (LoopInfo info : loops) {
+                    if (!intersection.contains(info)) {
+                        double loopFrequency = info.loopFrequency(nodeProbabilities);
+                        if (loopFrequency == -1) {
+                            return false;
+                        }
+                        probability *= loopFrequency;
+                    }
+                }
+                for (Probability other : withStates) {
+                    double prob = other.probability;
+                    for (LoopInfo info : other.loops) {
+                        if (!intersection.contains(info)) {
+                            double loopFrequency = info.loopFrequency(nodeProbabilities);
+                            if (loopFrequency == -1) {
+                                return false;
+                            }
+                            prob *= loopFrequency;
+                        }
+                    }
+                    probability += prob;
+                }
+                loops = intersection;
+                mergeLoops.put(merge, new HashSet<>(intersection));
+                assert isRelativeProbability(probability) : probability;
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+            loopInfo = new LoopInfo(loopBegin);
+            loopInfos.add(loopInfo);
+            loops.add(loopInfo);
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<Probability> loopEndStates) {
+            assert loopInfo != null;
+            List<LoopEndNode> loopEnds = loopBegin.orderedLoopEnds();
+            int i = 0;
+            for (Probability proba : loopEndStates) {
+                LoopEndNode loopEnd = loopEnds.get(i++);
+                Set<LoopInfo> requires = loopInfo.requires.get(loopEnd);
+                if (requires == null) {
+                    requires = new HashSet<>();
+                    loopInfo.requires.set(loopEnd, requires);
+                }
+                for (LoopInfo innerLoop : proba.loops) {
+                    if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) {
+                        requires.add(innerLoop);
+                    }
+                }
+            }
+            loopInfo.ended = true;
+        }
+
+        @Override
+        public void afterSplit(BeginNode node) {
+            assert node.predecessor() != null;
+            Node pred = node.predecessor();
+            if (pred instanceof Invoke) {
+                Invoke x = (Invoke) pred;
+                if (x.next() != node) {
+                    probability = 0;
+                }
+            } else {
+                assert pred instanceof ControlSplitNode;
+                ControlSplitNode x = (ControlSplitNode) pred;
+                probability *= x.probability(node);
+            }
+        }
+    }
+
+    private class PropagateProbability extends PostOrderNodeIterator<Probability> {
+
+        public PropagateProbability(FixedNode start) {
+            super(start, new Probability(1d, null));
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            nodeProbabilities.put(node, state.probability);
+        }
+    }
+
+    private class LoopCount implements MergeableState<LoopCount> {
+
+        public double count;
+
+        public LoopCount(double count) {
+            this.count = count;
+        }
+
+        @Override
+        public LoopCount clone() {
+            return new LoopCount(count);
+        }
+
+        @Override
+        public boolean merge(MergeNode merge, List<LoopCount> withStates) {
+            assert merge.forwardEndCount() == withStates.size() + 1;
+            if (merge.forwardEndCount() > 1) {
+                Set<LoopInfo> loops = mergeLoops.get(merge);
+                assert loops != null;
+                double countProd = 1;
+                for (LoopInfo loop : loops) {
+                    countProd *= loop.loopFrequency(nodeProbabilities);
+                }
+                count = countProd;
+            }
+            return true;
+        }
+
+        @Override
+        public void loopBegin(LoopBeginNode loopBegin) {
+            count *= loopBegin.loopFrequency();
+        }
+
+        @Override
+        public void loopEnds(LoopBeginNode loopBegin, List<LoopCount> loopEndStates) {
+            // nothing to do...
+        }
+
+        @Override
+        public void afterSplit(BeginNode node) {
+            // nothing to do...
+        }
+    }
+
+    private class PropagateLoopFrequency extends PostOrderNodeIterator<LoopCount> {
+
+        public PropagateLoopFrequency(FixedNode start) {
+            super(start, new LoopCount(1d));
+        }
+
+        @Override
+        protected void node(FixedNode node) {
+            nodeProbabilities.put(node, nodeProbabilities.get(node) * state.count);
+        }
+
+    }
+}
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon Apr 22 17:06:06 2013 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Mon Apr 22 17:49:13 2013 +0200
@@ -29,9 +29,9 @@
 import com.oracle.graal.debug.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
@@ -201,21 +201,21 @@
     }
 
     public static Map<Invoke, Double> getHints(StructuredGraph graph) {
-        NodeProbabilities probabilities = new ComputeProbabilityClosure(graph).run();
+        NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
         Map<Invoke, Double> hints = null;
         for (MaterializeObjectNode materialize : graph.getNodes(MaterializeObjectNode.class)) {
             double sum = 0;
             double invokeSum = 0;
             for (Node usage : materialize.usages()) {
                 if (usage instanceof FixedNode) {
-                    sum += probabilities.getProbability((FixedNode) usage);
+                    sum += probabilities.get((FixedNode) usage);
                 } else {
                     if (usage instanceof MethodCallTargetNode) {
-                        invokeSum += probabilities.getProbability(((MethodCallTargetNode) usage).invoke().asNode());
+                        invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
                     }
                     for (Node secondLevelUage : materialize.usages()) {
                         if (secondLevelUage instanceof FixedNode) {
-                            sum += probabilities.getProbability(((FixedNode) secondLevelUage));
+                            sum += probabilities.get(((FixedNode) secondLevelUage));
                         }
                     }
                 }