changeset 3197:4011431b4d85

Removed assertion in EdgeMoveOptimizer that is not valid anymore because of guards Made IdealGraph printing to network faster : use a buffered output stream Change in the scheduling of outer framestates : they would sometimes be pushed too high because of the inner framestate being attached to a merge Framestate now automatically delete their outerframestate if possible when the inner framestate is deleted Peeling : When coloring down, color the exception edges fix around framestates on 'dangling merges' allow some nodes to be white when splitting handle outerframestates properly when splitting
author Gilles Duboscq <gilles.duboscq@oracle.com>
date Thu, 07 Jul 2011 16:04:21 +0200
parents 03aca60eb99f
children adfd999fff7d
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/GraphUtil.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java
diffstat 9 files changed, 229 insertions(+), 155 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/EdgeMoveOptimizer.java	Thu Jul 07 16:04:21 2011 +0200
@@ -221,11 +221,11 @@
         // the instructions are inserted at the end of the block before these two branches
         int insertIdx = instructions.size() - 2;
 
-        if (GraalOptions.DetailedAsserts) {
+        if (GraalOptions.DetailedAsserts && false) { // not true anymore with guards
             for (int i = insertIdx - 1; i >= 0; i--) {
                 LIRInstruction op = instructions.get(i);
                 if ((op.code == LIROpcode.Branch || op.code == LIROpcode.CondFloatBranch) && ((LIRBranch) op).block() != null) {
-                    throw new Error("block with two successors can have only two branch instructions");
+                    throw new Error("block with two successors can have only two branch instructions : error in " + block);
                 }
             }
         }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Thu Jul 07 16:04:21 2011 +0200
@@ -229,14 +229,14 @@
             if (block != null) {
                 stream.printf("    <p name='block'>%d</p>%n", block.blockID());
                 if (!(node instanceof Phi || node instanceof FrameState || node instanceof Local || node instanceof LoopCounter) && !block.getInstructions().contains(node)) {
-                    stream.printf("    <p name='notInOwnBlock'>true</p>%n");
+                    stream.println("    <p name='notInOwnBlock'>true</p>");
                 }
             } else {
-                stream.printf("    <p name='block'>noBlock</p>%n");
+                stream.println("    <p name='block'>noBlock</p>");
                 noBlockNodes.add(node);
             }
             if (loopExits.isMarked(node)) {
-                stream.printf("    <p name='loopExit'>true</p>%n");
+                stream.println("    <p name='loopExit'>true</p>");
             }
             StringBuilder sb = new StringBuilder();
             if (loops != null) {
@@ -264,7 +264,7 @@
             Set<String> nodeBits = bits.get(node);
             if (nodeBits != null) {
                 for (String bit : nodeBits) {
-                    stream.printf("    <p name='");
+                    stream.print("    <p name='");
                     stream.print(bit);
                     stream.println("'>true</p>");
                 }
@@ -310,14 +310,14 @@
 
     private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) {
         stream.printf("   <block name='%d'>%n", block.blockID());
-        stream.printf("    <successors>%n");
+        stream.println("    <successors>");
         for (Block sux : block.getSuccessors()) {
             if (sux != null) {
                 stream.printf("     <successor name='%d'/>%n", sux.blockID());
             }
         }
-        stream.printf("    </successors>%n");
-        stream.printf("    <nodes>%n");
+        stream.println("    </successors>");
+        stream.println("    <nodes>");
 
         Set<Node> nodes = new HashSet<Node>(block.getInstructions());
 
@@ -360,7 +360,7 @@
                 }
             }
         }
-        stream.printf("    </nodes>%n");
+        stream.println("    </nodes>");
         stream.printf("   </block>%n", block.blockID());
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Thu Jul 07 16:04:21 2011 +0200
@@ -101,7 +101,7 @@
         try {
             socket = new Socket(host, port);
             if (socket.getInputStream().read() == 'y') {
-                stream = socket.getOutputStream();
+                stream = new BufferedOutputStream(socket.getOutputStream(), 0x4000);
             } else {
                 // server currently does not accept any input
                 socket.close();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Thu Jul 07 16:04:21 2011 +0200
@@ -1732,7 +1732,7 @@
             }
         }
         // the value must be a constant or have a valid operand
-        assert operand.isLegal() : "this root has not been visited yet; instruction=" + instruction;
+        assert operand.isLegal() : "this root has not been visited yet; instruction=" + instruction + " currentBlock=" + currentBlock;
         return operand;
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Thu Jul 07 16:04:21 2011 +0200
@@ -43,7 +43,7 @@
         if (GraalOptions.LoopPeeling) {
 peeling:
             for (Loop loop : loops) {
-    //            System.out.println("Peel loop : " + loop.loopBegin());
+                //System.out.println("Peel loop : " + loop.loopBegin());
                 for (Node exit : loop.exits()) {
                     if (!(exit instanceof StateSplit) || ((StateSplit) exit).stateAfter() == null) {
                         // TODO (gd) can not do loop peeling if an exit has no state. see LoopUtil.findNearestMergableExitPoint
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Thu Jul 07 16:04:21 2011 +0200
@@ -276,6 +276,8 @@
                         block = getCommonDominator(block, mergeBlock.getPredecessors().get(i));
                     }
                 }
+            } else if (usage instanceof FrameState && ((FrameState) usage).outerFrameState() == n) {
+                block = getCommonDominator(block, assignLatestPossibleBlockToNode(usage));
             } else if (usage instanceof FrameState && ((FrameState) usage).block() != null) {
                 Merge merge = ((FrameState) usage).block();
                 for (Node pred : merge.cfgPredecessors()) {
@@ -411,7 +413,7 @@
 
         int cnt = 0;
         while (!workList.isEmpty()) {
-            if (cnt++ > blocks.size() * 10) {
+            if (cnt++ > blocks.size() * 15) {
                 throw new RuntimeException("(ls) endless loop in computeDominators?");
             }
             Block b = workList.remove();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/GraphUtil.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/GraphUtil.java	Thu Jul 07 16:04:21 2011 +0200
@@ -82,36 +82,6 @@
                 colors.set(merge, color);
             }
         }
-
-
-        /*List<Node> startingPoints = new LinkedList<Node>();
-        for (Entry<Node, T> entry : colors.entries()) {
-            startingPoints.add(entry.getKey());
-        }
-        NodeWorkList work = colors.graph().createNodeWorkList();
-        for (Node startingPoint : startingPoints) {
-            if (startingPoint instanceof Merge) {
-                work.addAll(colorCFGDownToMerge(((Merge) startingPoint).next(), colors.get(startingPoint), colors));
-            } else {
-                work.addAll(colorCFGDownToMerge(startingPoint, colors.get(startingPoint), colors));
-            }
-        }
-        for (Node n : work) {
-            //System.out.println("Color : work on " + n);
-            Merge merge = (Merge) n;
-            ArrayList<T> incomming = new ArrayList<T>(2);
-            for (EndNode end : merge.cfgPredecessors()) {
-                incomming.add(colors.get(end));
-            }
-            T color = lambda.color(incomming, merge);
-            if (color != null) {
-                colors.set(merge, color);
-                work.addAll(colorCFGDownToMerge(merge.next(), color, colors));
-            } else {
-                System.out.println("Can not color " + merge);
-                work.addAgain(merge);
-            }
-        }*/
     }
 
     private static <T> Collection<Merge> colorCFGDownToMerge(Node from, T color, NodeMap<T> colors) {
@@ -129,7 +99,7 @@
                     break;
                 }
                 colors.set(current, color);
-                if (current instanceof FixedNodeWithNext) {
+                if (current instanceof FixedNodeWithNext && !(current instanceof Invoke && ((Invoke) current).exceptionEdge() != null)) {
                     current = ((FixedNodeWithNext) current).next();
                 } else if (current instanceof EndNode) {
                     current = ((EndNode) current).merge();
@@ -138,6 +108,10 @@
                         for (Node sux : current.cfgSuccessors()) {
                             work.add(sux);
                         }
+                    } else if (current instanceof Invoke && ((Invoke) current).exceptionEdge() != null) {
+                        Invoke invoke = (Invoke) current;
+                        work.add(invoke.next());
+                        work.add(invoke.exceptionEdge());
                     }
                     current = null;
                 }
@@ -152,6 +126,8 @@
         void fixNode(Node node, T color);
         Value fixPhiInput(Value input, T color);
         boolean explore(Node n);
+        List<T> parentColors(T color);
+        Merge merge(T color);
     }
 
     // TODO (gd) rework that code around Phi handling : too complicated
@@ -214,11 +190,14 @@
                             } else {
                                 T color = internalColoring.get(usage);
                                 if (color == null) {
-                                    //System.out.println("Split : color from " + usage + " is null");
-                                    delay = true;
-                                    break;
+                                    //System.out.println("Split : color from " + usage + " is null : " + (lambda.explore(usage) ? "Should be colored" : "Should be white"));
+                                    if (lambda.explore(usage)) {
+                                        delay = true;
+                                        break;
+                                    }
+                                } else {
+                                    colors.add(color);
                                 }
-                                colors.add(color);
                             }
                         }
                         if (delay) {
@@ -235,19 +214,44 @@
                         internalColoring.put(node, color);
                         lambda.fixNode(node, color);
                     } else {
-                        //System.out.println("Split : " + colors.size() + " colors, coloring, spliting, fixing");
-                        for (T color : colors) {
-                            Node newNode = node.copy();
-                            for (int i = 0; i < node.inputs().size(); i++) {
-                                Node input = node.inputs().get(i);
-                                newNode.inputs().setOrExpand(i, input);
+                        Map<T, Node> newNodes = new HashMap<T, Node>();
+                        Queue<T> colorQueue = new LinkedList<T>(colors);
+                        while (!colorQueue.isEmpty()) {
+                            T color = colorQueue.poll();
+                            List<T> parentColors = lambda.parentColors(color);
+                            Node newNode;
+                            if (parentColors.size() > 1 && !(node instanceof FrameState) && colors.containsAll(parentColors)) {
+                                boolean ready = true;
+                                for (T parentColor : parentColors) {
+                                    if (newNodes.get(parentColor) == null) {
+                                        ready = false;
+                                        break;
+                                    }
+                                }
+                                if (!ready) {
+                                    colorQueue.offer(color);
+                                    continue;
+                                }
+                                Phi phi = new Phi(((Value) node).kind, lambda.merge(color), node.graph());
+                                for (T parentColor : parentColors) {
+                                    Node input = newNodes.get(parentColor);
+                                    phi.addInput(input);
+                                }
+                                newNode = phi;
+                            } else {
+                                newNode = node.copy();
+                                for (int i = 0; i < node.inputs().size(); i++) {
+                                    Node input = node.inputs().get(i);
+                                    newNode.inputs().setOrExpand(i, input);
+                                }
+                                for (int i = 0; i < node.successors().size(); i++) {
+                                    Node input = node.successors().get(i);
+                                    newNode.successors().setOrExpand(i, input);
+                                }
+                                internalColoring.put(newNode, color);
+                                lambda.fixSplit(node, newNode, color);
                             }
-                            for (int i = 0; i < node.successors().size(); i++) {
-                                Node input = node.successors().get(i);
-                                newNode.successors().setOrExpand(i, input);
-                            }
-                            internalColoring.put(newNode, color);
-                            lambda.fixSplit(node, newNode, color);
+                            newNodes.put(color, newNode);
                             LinkedList<Node> dataUsages = new LinkedList<Node>();
                             for (Node usage : node.dataUsages()) {
                                 dataUsages.add(usage);
@@ -273,12 +277,15 @@
                                 }
                             }
                         }
+                        lambda.fixNode(node, null /*white*/);
                     }
                     if (node instanceof StateSplit) {
                         FrameState stateAfter = ((StateSplit) node).stateAfter();
                         if (stateAfter != null && lambda.explore(stateAfter) && !work.isNew(stateAfter)) {
                             //System.out.println("Split : Add framestate to work");
-                            work.add(stateAfter);
+                            if (!(node instanceof Merge && coloring.get(((Merge) node).next()) == null)) { // not dangling colored merge
+                                work.add(stateAfter);
+                            }
                         }
                     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Thu Jul 07 16:04:21 2011 +0200
@@ -81,7 +81,8 @@
         public final NodeMap<Placeholder> phis;
         public final NodeMap<Node> phiInits;
         public final NodeMap<Node> dataOut;
-        public PeelingResult(FixedNode begin, FixedNode end, NodeMap<StateSplit> exits, NodeMap<Placeholder> phis, NodeMap<Node> phiInits, NodeMap<Node> dataOut, NodeBitMap unaffectedExits) {
+        public final NodeBitMap exitFrameStates;
+        public PeelingResult(FixedNode begin, FixedNode end, NodeMap<StateSplit> exits, NodeMap<Placeholder> phis, NodeMap<Node> phiInits, NodeMap<Node> dataOut, NodeBitMap unaffectedExits, NodeBitMap exitFrameStates) {
             this.begin = begin;
             this.end = end;
             this.exits = exits;
@@ -89,6 +90,7 @@
             this.phiInits = phiInits;
             this.dataOut = dataOut;
             this.unaffectedExits = unaffectedExits;
+            this.exitFrameStates = exitFrameStates;
         }
     }
 
@@ -114,12 +116,7 @@
     public static NodeBitMap computeLoopExits(LoopBegin loopBegin, NodeBitMap nodes) {
         Graph graph = loopBegin.graph();
         NodeBitMap exits = graph.createNodeBitMap();
-        NodeFlood workCFG = graph.createNodeFlood();
-        workCFG.add(loopBegin.loopEnd());
-        for (Node n : workCFG) {
-            if (n == loopBegin) {
-                continue;
-            }
+        for (Node n : markUpCFG(loopBegin, loopBegin.loopEnd())) {
             if (IdentifyBlocksPhase.trueSuccessorCount(n) > 1) {
                 for (Node sux : n.cfgSuccessors()) {
                     if (!nodes.isMarked(sux) && sux instanceof FixedNode) {
@@ -127,9 +124,6 @@
                     }
                 }
             }
-            for (Node pred : n.cfgPredecessors()) {
-                workCFG.add(pred);
-            }
         }
         return exits;
     }
@@ -169,7 +163,8 @@
         }
         NodeBitMap inOrBefore = loopBegin.graph().createNodeBitMap();
         for (Node n : workData2) {
-            markWithState(n, inOrBefore);
+            //markWithState(n, inOrBefore);
+            inOrBefore.mark(n);
             if (n instanceof Phi) { // filter out data graph cycles
                 Phi phi = (Phi) n;
                 if (!phi.isDead()) {
@@ -195,8 +190,14 @@
                     workData2.add(usage);
                 }
             }
+            if (n instanceof StateSplit) {
+                FrameState stateAfter = ((StateSplit) n).stateAfter();
+                if (stateAfter != null) {
+                    workData2.add(stateAfter);
+                }
+            }
         }
-        if (!recurse) {
+        /*if (!recurse) {
             recurse = true;
             GraalCompilation compilation = GraalCompilation.compilation();
             if (compilation.compiler.isObserved()) {
@@ -207,7 +208,7 @@
                 compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Compute loop nodes loop#" + loopBegin.id(), loopBegin.graph(), true, false, debug));
             }
             recurse = false;
-        }
+        }*/
         inOrAfter.setIntersect(inOrBefore);
         loopNodes.setUnion(inOrAfter);
         return loopNodes;
@@ -276,9 +277,9 @@
             System.out.println("  - " + entry.getKey() + " -> " + entry.getValue());
         }*/
         rewirePeeling(peeling, loop, loopEnd);
-        if (compilation.compiler.isObserved()) {
+        /*if (compilation.compiler.isObserved()) {
             compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After rewirePeeling", loopEnd.graph(), true, false));
-        }
+        }*/
         // update parents
         Loop parent = loop.parent();
         while (parent != null) {
@@ -317,7 +318,14 @@
         for (Entry<Node, Placeholder> entry : peeling.phis.entries()) {
             Phi phi = (Phi) entry.getKey();
             Placeholder p = entry.getValue();
-            p.replaceAndDelete(phi.valueAt(phiInitIndex));
+            Value init = phi.valueAt(phiInitIndex);
+            p.replaceAndDelete(init);
+            for (Entry<Node, Node> dataEntry : peeling.dataOut.entries()) {
+                if (dataEntry.getValue() == p) {
+                    dataEntry.setValue(init);
+                    //System.out.println("Patch dataOut : " + dataEntry.getKey() + " -> " + dataEntry.getValue());
+                }
+            }
         }
         for (Entry<Node, Node> entry : peeling.phiInits.entries()) {
             Phi phi = (Phi) entry.getKey();
@@ -341,10 +349,10 @@
             EndNode oEnd = new EndNode(graph);
             EndNode nEnd = new EndNode(graph);
             Merge merge = new Merge(graph);
-            FrameState newState = newExit.stateAfter();
+            FrameState originalState = original.stateAfter();
             merge.addEnd(nEnd);
             merge.addEnd(oEnd);
-            merge.setStateAfter(newState.duplicate(newState.bci));
+            merge.setStateAfter(originalState.duplicate(originalState.bci, true));
             merge.setNext(original.next());
             original.setNext(oEnd);
             newExit.setNext(nEnd);
@@ -357,40 +365,20 @@
             EndNode oEnd = (EndNode) original.next();
             Merge merge = oEnd.merge();
             EndNode nEnd = merge.endAt(1 - merge.phiPredecessorIndex(oEnd));
-            FrameState newState = merge.stateAfter();
-            FrameState originalState = original.stateAfter();
-            while (newState != null) {
-                assert originalState != null;
-                NodeArray oInputs = originalState.inputs();
-                NodeArray nInputs = newState.inputs();
-                int oSize = oInputs.size();
-                for (int i = 1; i < oSize; i++) { // TODO (gd) start from 1 to avoid outer framestate, hacky..
-                    Node newValue = nInputs.get(i);
-                    Node originalValue = oInputs.get(i);
-                    if (newValue != originalValue) {
-                        Node newExit = nEnd.singlePredecessor();
-                        NodeMap<Value> phiMap = newExitValues.get(originalValue);
-                        if (phiMap == null) {
-                            phiMap = graph.createNodeMap();
-                            newExitValues.set(originalValue, phiMap);
-                        }
-                        phiMap.set(original, (Value) originalValue);
-                        phiMap.set(newExit, (Value) newValue);
+            Node newExit = nEnd.singlePredecessor();
+            for (Entry<Node, Node> dataEntry : peeling.dataOut.entries()) {
+                Node originalValue = dataEntry.getKey();
+                Node newValue = dataEntry.getValue();
+                NodeMap<Value> phiMap = newExitValues.get(originalValue);
+                if (phiMap == null) {
+                    phiMap = graph.createNodeMap();
+                    newExitValues.set(originalValue, phiMap);
+                }
+                phiMap.set(original, (Value) originalValue);
+                phiMap.set(newExit, (Value) newValue);
+            }
+        }
 
-                        phiMap = newExitValues.get(newValue);
-                        if (phiMap == null) {
-                            phiMap = graph.createNodeMap();
-                            newExitValues.set(newValue, phiMap);
-                        }
-                        phiMap.set(original, (Value) originalValue);
-                        phiMap.set(nEnd, (Value) newValue);
-                    }
-                }
-                newState = newState.outerFrameState();
-                originalState = originalState.outerFrameState();
-            }
-            assert originalState == null;
-        }
         for (Entry<Node, NodeMap<Value>> entry : newExitValues.entries()) {
             Value original = (Value) entry.getKey();
             NodeMap<Value> pointToValue = entry.getValue();
@@ -402,10 +390,10 @@
             }
         }
 
-        replaceValuesAtLoopExits(newExitValues, loop, exitPoints);
+        replaceValuesAtLoopExits(newExitValues, loop, exitPoints, peeling.exitFrameStates);
     }
 
-    private static void replaceValuesAtLoopExits(final NodeMap<NodeMap<Value>> newExitValues, Loop loop, List<Node> exitPoints) {
+    private static void replaceValuesAtLoopExits(final NodeMap<NodeMap<Value>> newExitValues, Loop loop, List<Node> exitPoints, final NodeBitMap exitFrameStates) {
         Graph graph = loop.loopBegin().graph();
         final NodeMap<Node> colors = graph.createNodeMap();
 
@@ -461,18 +449,20 @@
             Map<String, Object> debug = new HashMap<String, Object>();
             debug.put("loopExits", colors);
             debug.put("inOrBefore", inOrBefore);
+            debug.put("exitFrameStates", exitFrameStates);
             compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After coloring", graph, true, false, debug));
         }
 
         GraphUtil.splitFromColoring(colors, new ColorSplitingLambda<Node>(){
             @Override
             public void fixSplit(Node oldNode, Node newNode, Node color) {
+                assert color != null;
                 this.fixNode(newNode, color);
             }
             private Value getValueAt(Node point, NodeMap<Value> valueMap, CiKind kind) {
                 Value value = valueMap.get(point);
                 if (value != null) {
-                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + value);
+                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = (cached) " + value);
                     return value;
                 }
                 Merge merge = (Merge) point;
@@ -494,31 +484,45 @@
                     for (EndNode end : merge.cfgPredecessors()) {
                         phi.addInput(getValueAt(colors.get(end), valueMap, kind));
                     }
-                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + phi);
+                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = (new-phi) " + phi);
                     return phi;
                 } else {
                     assert v != null;
                     valueMap.set(point, v);
-                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + v);
+                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = (unique) " + v);
                     return v;
                 }
             }
             @Override
             public boolean explore(Node n) {
-                return !inOrBefore.isNew(n) && !inOrBefore.isMarked(n) && !(n instanceof Local) && !(n instanceof Constant); //TODO (gd) hum
+                return (!exitFrameStates.isNew(n) && exitFrameStates.isMarked(n))
+                || (!inOrBefore.isNew(n) && !inOrBefore.isMarked(n) && !(n instanceof Local) && !danglingMergeFrameState(n)); //TODO (gd) hum
+            }
+            public boolean danglingMergeFrameState(Node n) {
+                if (!(n instanceof FrameState)) {
+                    return false;
+                }
+                Merge block = ((FrameState) n).block();
+                return block != null && colors.get(block.next()) == null;
             }
             @Override
             public void fixNode(Node node, Node color) {
                 //System.out.println("fixNode(" + node + ", " + color + ")");
-                for (int i = 0; i < node.inputs().size(); i++) {
-                    Node input = node.inputs().get(i);
-                    if (input == null || newExitValues.isNew(input)) {
-                        continue;
-                    }
-                    NodeMap<Value> valueMap = newExitValues.get(input);
-                    if (valueMap != null) {
-                        Value replacement = getValueAt(color, valueMap, ((Value) input).kind);
-                        node.inputs().set(i, replacement);
+                if (color == null) {
+                    // 'white' it out : make non-explorable
+                    exitFrameStates.clear(node);
+                    inOrBefore.mark(node);
+                } else {
+                    for (int i = 0; i < node.inputs().size(); i++) {
+                        Node input = node.inputs().get(i);
+                        if (input == null || newExitValues.isNew(input)) {
+                            continue;
+                        }
+                        NodeMap<Value> valueMap = newExitValues.get(input);
+                        if (valueMap != null) {
+                            Value replacement = getValueAt(color, valueMap, ((Value) input).kind);
+                            node.inputs().set(i, replacement);
+                        }
                     }
                 }
             }
@@ -532,11 +536,28 @@
                     return getValueAt(color, valueMap, input.kind);
                 }
                 return input;
-            }});
+            }
+            @Override
+            public List<Node> parentColors(Node color) {
+                if (!(color instanceof Merge)) {
+                    return Collections.emptyList();
+                }
+                Merge merge = (Merge) color;
+                List<Node> parentColors = new ArrayList<Node>(merge.phiPredecessorCount());
+                for (Node pred : merge.phiPredecessors()) {
+                    parentColors.add(colors.get(pred));
+                }
+                return parentColors;
+            }
+            @Override
+            public Merge merge(Node color) {
+                return (Merge) color;
+            }
+        });
 
-        if (compilation.compiler.isObserved()) {
+        /*if (compilation.compiler.isObserved()) {
             compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After split from colors", graph, true, false));
-        }
+        }*/
     }
 
     private static PeelingResult preparePeeling(Loop loop, FixedNode from) {
@@ -544,11 +565,11 @@
         Graph graph = loopBegin.graph();
         NodeBitMap marked = computeLoopNodesFrom(loopBegin, from);
         GraalCompilation compilation = GraalCompilation.compilation();
-        if (compilation.compiler.isObserved()) {
+        /*if (compilation.compiler.isObserved()) {
             Map<String, Object> debug = new HashMap<String, Object>();
             debug.put("marked", marked);
             compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After computeLoopNodesFrom", loopBegin.graph(), true, false, debug));
-        }
+        }*/
         if (from == loopBegin.loopEnd()) {
             clearWithState(from, marked);
         }
@@ -558,16 +579,35 @@
         NodeMap<StateSplit> exits = graph.createNodeMap();
         NodeBitMap unaffectedExits = graph.createNodeBitMap();
         NodeBitMap clonedExits = graph.createNodeBitMap();
+        NodeBitMap exitFrameStates = graph.createNodeBitMap();
         for (Node exit : loop.exits()) {
             if (marked.isMarked(exit.singlePredecessor())) {
                 StateSplit pExit = findNearestMergableExitPoint(exit, marked);
                 markWithState(pExit, marked);
                 clonedExits.mark(pExit);
+                FrameState stateAfter = pExit.stateAfter();
+                while (stateAfter != null) {
+                    exitFrameStates.mark(stateAfter);
+                    stateAfter = stateAfter.outerFrameState();
+                }
             } else {
                 unaffectedExits.mark(exit);
             }
         }
 
+        NodeBitMap dataOut = graph.createNodeBitMap();
+        for (Node n : marked) {
+            if (!(n instanceof FrameState)) {
+                for (Node usage : n.dataUsages()) {
+                    if ((!marked.isMarked(usage) && !((usage instanceof Phi) && ((Phi) usage).merge() != loopBegin))
+                                    || (marked.isMarked(usage) && exitFrameStates.isMarked(usage))) {
+                        dataOut.mark(n);
+                        break;
+                    }
+                }
+            }
+        }
+
         for (Node n : marked) {
             if (n instanceof Phi && ((Phi) n).merge() == loopBegin) {
                 Placeholder p = new Placeholder(graph);
@@ -591,37 +631,45 @@
 
         Map<Node, Node> duplicates = graph.addDuplicate(marked, replacements);
 
+        /*System.out.println("Dup mapping :");
+        for (Entry<Node, Node> entry : duplicates.entrySet()) {
+            System.out.println(" - " + entry.getKey().id() + " -> " + entry.getValue().id());
+        }*/
+
+        NodeMap<Node> dataOutMapping = graph.createNodeMap();
+        for (Node n : dataOut) {
+            Node newOut = duplicates.get(n);
+            if (newOut == null) {
+                newOut = replacements.get(n);
+            }
+            assert newOut != null;
+            dataOutMapping.set(n, newOut);
+        }
+
         for (Node n : clonedExits) {
             exits.set(n, (StateSplit) duplicates.get(n));
         }
 
-        NodeMap<Node> dataOut = graph.createNodeMap();
-        for (Node n : marked) {
-            for (Node usage : n.dataUsages()) {
-                if (!marked.isMarked(usage)
-                                && !loop.nodes().isNew(usage) && loop.nodes().isMarked(usage)
-                                && !((usage instanceof Phi) && ((Phi) usage).merge() != loopBegin)) {
-                    dataOut.set(n, duplicates.get(n));
-                    break;
+        NodeMap<Node> phiInits = graph.createNodeMap();
+        if (from == loopBegin.loopEnd()) {
+            int backIndex = loopBegin.phiPredecessorIndex(loopBegin.loopEnd());
+            int fowardIndex = loopBegin.phiPredecessorIndex(loopBegin.forwardEdge());
+            for (Phi phi : loopBegin.phis()) {
+                Value backValue = phi.valueAt(backIndex);
+                if (marked.isMarked(backValue)) {
+                    phiInits.set(phi, duplicates.get(backValue));
+                } else if (backValue instanceof Phi && ((Phi) backValue).merge() == loopBegin) {
+                    Phi backPhi = (Phi) backValue;
+                    phiInits.set(phi, backPhi.valueAt(fowardIndex));
+                } else {
+                    phiInits.set(phi, backValue);
                 }
             }
         }
-        NodeMap<Node> phiInits = graph.createNodeMap();
-        int backIndex = loopBegin.phiPredecessorIndex(loopBegin.loopEnd());
-        int fowardIndex = loopBegin.phiPredecessorIndex(loopBegin.forwardEdge());
-        for (Phi phi : loopBegin.phis()) {
-            Value backValue = phi.valueAt(backIndex);
-            if (marked.isMarked(backValue)) {
-                phiInits.set(phi, duplicates.get(backValue));
-            } else if (backValue instanceof Phi && ((Phi) backValue).merge() == loopBegin) {
-                Phi backPhi = (Phi) backValue;
-                phiInits.set(phi, backPhi.valueAt(fowardIndex));
-            }
-        }
 
         FixedNode newBegin = (FixedNode) duplicates.get(loopBegin.next());
         FixedNode newFrom = (FixedNode) duplicates.get(from == loopBegin.loopEnd() ? from.singlePredecessor() : from);
-        return new PeelingResult(newBegin, newFrom, exits, phis, phiInits, dataOut, unaffectedExits);
+        return new PeelingResult(newBegin, newFrom, exits, phis, phiInits, dataOutMapping, unaffectedExits, exitFrameStates);
     }
 
     private static StateSplit findNearestMergableExitPoint(Node exit, NodeBitMap marked) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Tue Jul 05 11:42:28 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Thu Jul 07 16:04:21 2011 +0200
@@ -129,9 +129,17 @@
      * Gets a copy of this frame state.
      */
     public FrameState duplicate(int bci) {
+        return duplicate(bci, false);
+    }
+
+    public FrameState duplicate(int bci, boolean duplicateOuter) {
         FrameState other = new FrameState(method, bci, localsSize, stackSize, locksSize, rethrowException, graph());
         other.inputs().setAll(inputs());
-        other.setOuterFrameState(outerFrameState());
+        FrameState outerFrameState = outerFrameState();
+        if (duplicateOuter && outerFrameState != null) {
+            outerFrameState = outerFrameState.duplicate(outerFrameState.bci, duplicateOuter);
+        }
+        other.setOuterFrameState(outerFrameState);
         return other;
     }
 
@@ -567,6 +575,15 @@
     }
 
     @Override
+    public void delete() {
+        FrameState outerFrameState = outerFrameState();
+        super.delete();
+        if (outerFrameState != null && outerFrameState.usages().isEmpty()) {
+            outerFrameState.delete();
+        }
+    }
+
+    @Override
     public Node copy(Graph into) {
         return new FrameState(method, bci, localsSize, stackSize, locksSize, rethrowException, into);
     }