changeset 3131:5c696a58e692

Merge.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Fri, 01 Jul 2011 19:39:29 +0200
parents a4b0c3df7f80 (current diff) c3573103764e (diff)
children 20058d88555b
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java
diffstat 14 files changed, 257 insertions(+), 132 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalMetrics.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalMetrics.java	Fri Jul 01 19:39:29 2011 +0200
@@ -62,6 +62,7 @@
     public static int FrameStatesCreated;
     public static int FrameStateValuesCreated;
     public static int NodesCanonicalized;
+    public static int LoopsPeeled;
 
     public static void print() {
         for (Entry<String, GraalMetrics> m : map.entrySet()) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Jul 01 19:39:29 2011 +0200
@@ -59,6 +59,7 @@
     public static boolean EscapeAnalysis                     = ____;
     public static int     ForcedInlineEscapeWeight           = 0;
     public static int     MaximumEscapeAnalysisArrayLength   = 32;
+    public static boolean PrintEscapeAnalysis                = ____;
 
     // debugging settings
     public static boolean VerifyPointerMaps                  = ____;
@@ -155,4 +156,5 @@
     public static boolean OptGVN                             = true;
     public static boolean OptCanonicalizer                   = true;
     public static boolean OptLoops                           = true;
+    public static boolean LoopPeeling                        = ____;
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Fri Jul 01 19:39:29 2011 +0200
@@ -642,7 +642,7 @@
                                 if (!liveKill.get(operandNum)) {
                                     liveGen.set(operandNum);
                                     if (GraalOptions.TraceLinearScanLevel >= 4) {
-                                        TTY.println("  Setting liveGen for value %s, LIR opId %d, operand %d because of state for " + op.toString(), Util.valueString(value), op.id(), operandNum);
+                                        TTY.println("  Setting liveGen for value %s, LIR opId %d, operand %d because of state for %s", Util.valueString(value), op.id(), operandNum, op);
                                     }
                                 }
                             } else if (operand.isRegister()) {
@@ -1270,17 +1270,9 @@
                 if (info != null) {
                     info.state.forEachLiveStateValue(new ValueProcedure() {
                         public void doValue(Value value) {
-                            if (value instanceof VirtualObject) {
-                                VirtualObject obj = (VirtualObject) value;
-                                do {
-                                    doValue(obj.input());
-                                    obj = obj.object();
-                                } while (obj != null);
-                            } else {
-                                CiValue operand = value.operand();
-                                if (operand.isVariableOrRegister()) {
-                                    addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null);
-                                }
+                            CiValue operand = value.operand();
+                            if (operand.isVariableOrRegister()) {
+                                addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null);
                             }
                         }
                     });
@@ -1899,6 +1891,7 @@
         RiType type = obj.type();
         EscapeField[] escapeFields = obj.fields();
         CiValue[] values = new CiValue[escapeFields.length];
+        int valuesFilled = 0;
 
         VirtualObject current = obj;
         do {
@@ -1907,6 +1900,7 @@
                 if (escapeFields[i].representation() == current.field().representation()) {
                     if (values[i] == null) {
                         values[i] = toCiValue(opId, current.input());
+                        valuesFilled++;
                     }
                     found = true;
                     break;
@@ -1914,7 +1908,7 @@
             }
             assert found : type + "." + current.field() + " not found";
             current = current.object();
-        } while (current != null);
+        } while (current != null && valuesFilled < values.length);
 
         for (int i = 0; i < escapeFields.length; i++) {
             assert values[i] != null : type + "." + escapeFields[i];
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Fri Jul 01 19:39:29 2011 +0200
@@ -264,14 +264,20 @@
             Set<String> nodeBits = bits.get(node);
             if (nodeBits != null) {
                 for (String bit : nodeBits) {
-                    stream.printf("    <p name='%s'>true</p>%n", bit);
+                    stream.printf("    <p name='");
+                    stream.print(bit);
+                    stream.println("'>true</p>");
                 }
             }
 
             for (Entry<Object, Object> entry : props.entrySet()) {
                 String key = entry.getKey().toString();
                 String value = entry.getValue() == null ? "null" : entry.getValue().toString();
-                stream.printf("    <p name='%s'>%s</p>%n", escape(key), escape(value));
+                stream.print("    <p name='");
+                stream.print(escape(key));
+                stream.print("'>");
+                stream.print(escape(value));
+                stream.println("</p>");
             }
 
             stream.println("   </properties></node>");
@@ -371,11 +377,50 @@
     }
 
     private String escape(String s) {
-        s = s.replace("&", "&amp;");
-        s = s.replace("<", "&lt;");
-        s = s.replace(">", "&gt;");
-        s = s.replace("\"", "&quot;");
-        s = s.replace("'", "&apos;");
-        return s;
+        StringBuilder str = null;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '&':
+                case '<':
+                case '>':
+                case '"':
+                case '\'':
+                    if (str == null) {
+                        str = new StringBuilder();
+                        str.append(s, 0, i);
+                    }
+                    switch(c) {
+                        case '&':
+                            str.append("&amp;");
+                            break;
+                        case '<':
+                            str.append("&lt;");
+                            break;
+                        case '>':
+                            str.append("&gt;");
+                            break;
+                        case '"':
+                            str.append("&quot;");
+                            break;
+                        case '\'':
+                            str.append("&apos;");
+                            break;
+                        default:
+                            assert false;
+                    }
+                    break;
+                default:
+                    if (str != null) {
+                        str.append(c);
+                    }
+                    break;
+            }
+        }
+        if (str == null) {
+            return s;
+        } else {
+            return str.toString();
+        }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jul 01 19:39:29 2011 +0200
@@ -1645,10 +1645,18 @@
     }
 
     private void walkVirtualObject(VirtualObject value) {
-        walkStateValue(value.input());
-        if (value.object() != null) {
-            walkVirtualObject(value.object());
+        if (value.input() instanceof Phi) {
+            assert !((Phi) value.input()).isDead();
         }
+        HashSet<Object> fields = new HashSet<Object>();
+        VirtualObject obj = value;
+        do {
+            if (!fields.contains(obj.field().representation())) {
+                fields.add(obj.field().representation());
+                walkStateValue(obj.input());
+            }
+            obj = obj.object();
+        } while (obj != null);
     }
 
     protected LIRDebugInfo stateFor(Value x) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Fri Jul 01 19:39:29 2011 +0200
@@ -93,6 +93,13 @@
 
     public abstract CiKind elementKind();
 
+    @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> properties = super.getDebugProperties();
+        properties.put("exactType", exactType());
+        return properties;
+    }
+
     @SuppressWarnings("unchecked")
     @Override
     public <T extends Op> T lookup(Class<T> clazz) {
@@ -200,7 +207,7 @@
         }
 
         @Override
-        public void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState) {
+        public EscapeField updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Value> fieldState) {
             if (current instanceof AccessIndexed) {
                 int index = ((AccessIndexed) current).index().asConstant().asInt();
                 EscapeField field = fields.get(index);
@@ -220,9 +227,11 @@
                         fieldState.put(field, x.value());
                         assert x.usages().size() == 0;
                         x.replaceAndDelete(x.next());
+                        return field;
                     }
                 }
             }
+            return null;
         }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Fri Jul 01 19:39:29 2011 +0200
@@ -87,6 +87,14 @@
     }
 
     @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> properties = super.getDebugProperties();
+        properties.put("instanceClass", instanceClass);
+        properties.put("cpi", cpi);
+        return properties;
+    }
+
+    @Override
     public Node copy(Graph into) {
         NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into);
         return x;
@@ -187,7 +195,7 @@
         }
 
         @Override
-        public void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState) {
+        public EscapeField updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Value> fieldState) {
             if (current instanceof AccessField) {
                 EscapeField field = fields.get(((AccessField) current).field());
                 if (current instanceof LoadField) {
@@ -206,9 +214,11 @@
                         fieldState.put(field, x.value());
                         assert x.usages().size() == 0;
                         x.replaceAndDelete(x.next());
+                        return field;
                     }
                 }
             }
+            return null;
         }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java	Fri Jul 01 19:39:29 2011 +0200
@@ -101,6 +101,7 @@
         assert this.operand.isIllegal() : "operand cannot be set twice";
         assert operand != null && operand.isLegal() : "operand must be legal";
         assert operand.kind.stackKind() == this.kind;
+        assert !(this instanceof VirtualObject);
         this.operand = operand;
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Jul 01 19:39:29 2011 +0200
@@ -30,6 +30,7 @@
 import com.oracle.max.graal.compiler.gen.*;
 import com.oracle.max.graal.compiler.graph.*;
 import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.observer.*;
 import com.oracle.max.graal.compiler.schedule.*;
 import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
@@ -41,11 +42,11 @@
 
 
     public static class BlockExitState {
-        public final Map<EscapeField, Node> fieldState;
+        public final Map<EscapeField, Value> fieldState;
         public VirtualObject obj;
 
         public BlockExitState() {
-            this.fieldState = new HashMap<EscapeField, Node>();
+            this.fieldState = new HashMap<EscapeField, Value>();
         }
     }
 
@@ -101,7 +102,7 @@
 //                    TTY.println();
 
                     BlockExitState state = new BlockExitState();
-                    if (block == startBlock) {
+                    if (/*block == startBlock ||*/ block.getPredecessors().size() == 0) {
                         state.obj = null;
                         for (EscapeField field : fields.values()) {
                             Constant value = Constant.defaultForKind(field.kind(), graph);
@@ -150,7 +151,10 @@
                     }
                     while (current != block.lastNode()) {
                         Node next = ((FixedNodeWithNext) current).next();
-                        op.updateState(node, current, fields, state.fieldState);
+                        EscapeField changedField = op.updateState(node, current, fields, state.fieldState);
+                        if (changedField != null) {
+                            state.obj = new VirtualObject(state.obj, state.fieldState.get(changedField), changedField, type, escapeFields, graph);
+                        }
                         if (!current.isDeleted() && current instanceof StateSplit) {
                             FrameState stateAfter = ((StateSplit) current).stateAfter();
                             if (stateAfter != null) {
@@ -162,14 +166,14 @@
 
                     if (GraalOptions.TraceEscapeAnalysis) {
                         TTY.print(" block end state: ");
-                        for (Entry<EscapeField, Node> entry : state.fieldState.entrySet()) {
+                        for (Entry<EscapeField, Value> entry : state.fieldState.entrySet()) {
                             TTY.print("%s->%s ", entry.getKey().name(), entry.getValue());
                         }
                         TTY.println();
                     }
                     exitStates.put(block, state);
                 }
-            }, startBlock);
+            });
 
             for (Entry<Phi, EscapeField> entry : phis.entrySet()) {
                 Phi phi = entry.getKey();
@@ -208,7 +212,7 @@
             }
             // the rest of the usages should be dead frame states...
             for (Node usage : new ArrayList<Node>(node.usages())) {
-                assert usage instanceof FrameState || usage instanceof VirtualObject;
+                assert usage instanceof FrameState || usage instanceof VirtualObject : "usage: " + usage;
                 usage.inputs().replace(node, Node.Null);
             }
 
@@ -231,8 +235,19 @@
                     } while (obj != null);
                 }
             }
-            if (frameState.outerFrameState() != null) {
-                current = updateFrameState(frameState.outerFrameState(), current);
+            FrameState outer = frameState.outerFrameState();
+            if (outer != null) {
+                boolean duplicate = false;
+                for (int i = 0; i < outer.inputs().size(); i++) {
+                    if (outer.inputs().get(i) == node) {
+                        duplicate = true;
+                    }
+                }
+                if (duplicate) {
+                    outer = outer.duplicate(outer.bci);
+                    frameState.setOuterFrameState(outer);
+                }
+                current = updateFrameState(outer, current);
             }
             return current;
         }
@@ -251,7 +266,8 @@
         }
 
         private void process() {
-            for (Node usage : new ArrayList<Node>(node.usages())) {
+            ArrayList<Node> arrayList = new ArrayList<Node>(node.usages());
+            for (Node usage : arrayList) {
                 op.beforeUpdate(node, usage);
             }
         }
@@ -267,10 +283,9 @@
 
     @Override
     protected void run(Graph graph) {
-//        if (!compilation.method.holder().name().contains("jnt")) {
+//        if (compilation.method.holder().name().contains("oracle")) {
 //            return;
 //        }
-//        if (true) return;
         for (Node node : graph.getNodes()) {
             EscapeOp op = node.lookup(EscapeOp.class);
             if (op != null && op.canAnalyze(node)) {
@@ -283,30 +298,39 @@
                 do {
                     weight = analyze(op, node, exits, invokes);
                     if (exits.size() != 0) {
-                        if (GraalOptions.TraceEscapeAnalysis) {
-                            TTY.println("####### escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method);
-                            TTY.print("%d: new value: %d %s, weight %d, escapes at ", iterations, node.id(), node.shortName(), weight);
-                            for (Node n : exits) {
-                                TTY.print("%d %s, ", n.id(), n.shortName());
+                        if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) {
+                            TTY.println("%n####### escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method);
+                            if (GraalOptions.TraceEscapeAnalysis) {
+                                TTY.print("%d: new value: %d %s, weight %d, escapes at ", iterations, node.id(), node.shortName(), weight);
+                                for (Node n : exits) {
+                                    TTY.print("%d %s, ", n.id(), n.shortName());
+                                }
+                                for (Node n : invokes) {
+                                    TTY.print("%d %s, ", n.id(), n.shortName());
+                                }
+                                TTY.println();
                             }
-                            for (Node n : invokes) {
-                                TTY.print("%d %s, ", n.id(), n.shortName());
-                            }
-                            TTY.println();
                         }
                         break;
                     }
                     if (invokes.size() == 0) {
-                        if (GraalOptions.TraceEscapeAnalysis) {
-                            TTY.println("!!!!!!!! non-escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method);
+
+                        if (compilation.compiler.isObserved()) {
+                            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Before escape " + node.id(), graph, true, false));
+                        }
+                        if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) {
+                            TTY.println("%n!!!!!!!! non-escaping object: %d %s (%s) in %s", node.id(), node.shortName(), ((Value) node).exactType(), compilation.method);
                         }
                         new EscapementFixup(op, graph, node).apply();
                         new PhiSimplifier(graph);
+                        if (compilation.compiler.isObserved()) {
+                            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After escape " + node.id(), graph, true, false));
+                        }
                         break;
                     }
                     if (weight < minimumWeight) {
-                        if (GraalOptions.TraceEscapeAnalysis) {
-                            TTY.println("####### possibly escaping object: %d in %s (insufficient weight for inlining)", node.id(), compilation.method);
+                        if (GraalOptions.TraceEscapeAnalysis || GraalOptions.PrintEscapeAnalysis) {
+                            TTY.println("%n####### possibly escaping object: %d in %s (insufficient weight for inlining)", node.id(), compilation.method);
                         }
                         break;
                     }
@@ -381,7 +405,7 @@
 
         void beforeUpdate(Node node, Node usage);
 
-        void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState);
+        EscapeField updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Value> fieldState);
 
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Fri Jul 01 19:39:29 2011 +0200
@@ -24,6 +24,7 @@
 
 import java.util.*;
 
+import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.compiler.util.LoopUtil.Loop;
@@ -38,14 +39,24 @@
     protected void run(Graph graph) {
         List<Loop> loops = LoopUtil.computeLoops(graph);
 
-//        for (Loop loop : loops) {
-//            System.out.println("Peel loop : " + loop.loopBegin());
-//            LoopUtil.peelLoop(loop);
-//        }
-//        loops = LoopUtil.computeLoops(graph); // TODO (gd) avoid recomputing loops
-
-        for (Loop loop : loops) {
-            doLoopCounters(loop);
+        // TODO (gd) currently counter detection is disabled when loop peeling is active
+        if (GraalOptions.LoopPeeling) {
+peeling:
+            for (Loop loop : loops) {
+    //            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
+                        continue peeling;
+                    }
+                }
+                LoopUtil.peelLoop(loop);
+            }
+        } else {
+//            loops = LoopUtil.computeLoops(graph); // TODO (gd) avoid recomputing loops
+            for (Loop loop : loops) {
+                doLoopCounters(loop);
+            }
         }
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Fri Jul 01 19:39:29 2011 +0200
@@ -408,7 +408,11 @@
             }
         }
 
+        int cnt = 0;
         while (!workList.isEmpty()) {
+            if (cnt++ > blocks.size() * 10) {
+                throw new RuntimeException("(ls) endless loop in computeDominators?");
+            }
             Block b = workList.remove();
 
             List<Block> predecessors = b.getPredecessors();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Fri Jul 01 19:39:29 2011 +0200
@@ -76,17 +76,19 @@
     private static class PeelingResult {
         public final FixedNode begin;
         public final FixedNode end;
-        public final NodeMap<Placeholder> exits;
+        public final NodeMap<StateSplit> exits;
+        public final NodeBitMap unaffectedExits;
         public final NodeMap<Placeholder> phis;
         public final NodeMap<Node> phiInits;
         public final NodeMap<Node> dataOut;
-        public PeelingResult(FixedNode begin, FixedNode end, NodeMap<Placeholder> exits, NodeMap<Placeholder> phis, NodeMap<Node> phiInits, NodeMap<Node> dataOut) {
+        public PeelingResult(FixedNode begin, FixedNode end, NodeMap<StateSplit> exits, NodeMap<Placeholder> phis, NodeMap<Node> phiInits, NodeMap<Node> dataOut, NodeBitMap unaffectedExits) {
             this.begin = begin;
             this.end = end;
             this.exits = exits;
             this.phis = phis;
             this.phiInits = phiInits;
             this.dataOut = dataOut;
+            this.unaffectedExits = unaffectedExits;
         }
     }
 
@@ -230,7 +232,7 @@
         return loopNodes;
     }
 
-    public static void ifDoWhileTransform(Loop loop, If split) {
+    public static void inverseLoop(Loop loop, If split) {
         assert loop.nodes().isMarked(split);
         FixedNode noExit = split.trueSuccessor();
         FixedNode exit = split.falseSuccessor();
@@ -284,6 +286,7 @@
             parent.exits = computeLoopExits(parent.loopBegin, parent.nodes);
             parent = parent.parent;
         }
+        GraalMetrics.LoopsPeeled++;
     }
 
     private static void rewirePeeling(PeelingResult peeling, Loop loop, FixedNode from) {
@@ -329,79 +332,64 @@
         }
         NodeMap<NodeMap<Value>> newExitValues = graph.createNodeMap();
         List<Node> exitPoints = new LinkedList<Node>();
-        for (Node exit : loop.exits()) {
+        for (Node exit : peeling.unaffectedExits) {
             exitPoints.add(exit);
         }
-        for (Entry<Node, Placeholder> entry : peeling.exits.entries()) {
-            Placeholder original = (Placeholder) entry.getKey();
-            Placeholder newExit = entry.getValue();
-            FixedNode next = original.next();
+        for (Entry<Node, StateSplit> entry : peeling.exits.entries()) {
+            StateSplit original = (StateSplit) entry.getKey();
+            StateSplit newExit = entry.getValue();
             EndNode oEnd = new EndNode(graph);
             EndNode nEnd = new EndNode(graph);
             Merge merge = new Merge(graph);
-            merge.setNext(next);
             FrameState newState = newExit.stateAfter();
             merge.addEnd(nEnd);
-            merge.setStateAfter(newState);
-            //newState.merge(merge, original.stateAfter());
             merge.addEnd(oEnd);
+            merge.setStateAfter(newState.duplicate(newState.bci));
+            merge.setNext(original.next());
             original.setNext(oEnd);
-            newExit.setStateAfter(null);
-            newExit.replaceAndDelete(nEnd);
-
-            exitPoints.add(nEnd);
+            newExit.setNext(nEnd);
+            exitPoints.add(original);
+            exitPoints.add(newExit);
         }
 
-        for (Entry<Node, Placeholder> entry : peeling.exits.entries()) {
-            Placeholder original = (Placeholder) entry.getKey();
+        for (Entry<Node, StateSplit> entry : peeling.exits.entries()) {
+            StateSplit original = (StateSplit) entry.getKey();
             EndNode oEnd = (EndNode) original.next();
             Merge merge = oEnd.merge();
             EndNode nEnd = merge.endAt(1 - merge.phiPredecessorIndex(oEnd));
             FrameState newState = merge.stateAfter();
-            NodeArray oInputs = original.stateAfter().inputs();
-            NodeArray nInputs = newState.inputs();
-            int oSize = oInputs.size();
-            for (int i = 0; i < oSize; i++) {
-                Node newValue = nInputs.get(i);
-                Node originalValue = oInputs.get(i);
-                if (newValue != originalValue) {
-                    NodeMap<Value> phiMap = newExitValues.get(originalValue);
-                    if (phiMap == null) {
-                        phiMap = graph.createNodeMap();
-                        newExitValues.set(originalValue, phiMap);
-                    }
-                    phiMap.set(original, (Value) originalValue);
-                    phiMap.set(nEnd, (Value) newValue);
+            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);
 
-                    phiMap = newExitValues.get(newValue);
-                    if (phiMap == null) {
-                        phiMap = graph.createNodeMap();
-                        newExitValues.set(newValue, phiMap);
+                        phiMap = newExitValues.get(newValue);
+                        if (phiMap == null) {
+                            phiMap = graph.createNodeMap();
+                            newExitValues.set(newValue, phiMap);
+                        }
+                        phiMap.set(original, (Value) originalValue);
+                        phiMap.set(nEnd, (Value) newValue);
                     }
-                    phiMap.set(original, (Value) originalValue);
-                    phiMap.set(nEnd, (Value) newValue);
                 }
+                newState = newState.outerFrameState();
+                originalState = originalState.outerFrameState();
             }
-            /*Placeholder original = (Placeholder) entry.getKey();
-            Merge merge = ((EndNode) original.next()).merge();
-            FrameState newState = merge.stateAfter();
-            NodeArray oInputs = original.stateAfter().inputs();
-            NodeArray nInputs = newState.inputs();
-            int oSize = oInputs.size();
-            for (int i = 0; i < oSize; i++) {
-                Node newValue = nInputs.get(i);
-                Node originalValue = oInputs.get(i);
-                if (newValue != originalValue && newValue instanceof Phi) {
-                    Phi newPhi = (Phi) newValue;
-                    assert newPhi.valueAt(1) == originalValue;
-                    NodeMap<Value> phiMap = newExitValues.get(originalValue);
-                    if (phiMap == null) {
-                        phiMap = graph.createNodeMap();
-                        newExitValues.set(originalValue, phiMap);
-                    }
-                    phiMap.set(merge, newPhi);
-                }
-            }*/
+            assert originalState == null;
         }
         for (Entry<Node, NodeMap<Value>> entry : newExitValues.entries()) {
             Value original = (Value) entry.getKey();
@@ -567,15 +555,16 @@
         clearWithState(loopBegin, marked);
         Map<Node, Node> replacements = new HashMap<Node, Node>();
         NodeMap<Placeholder> phis = graph.createNodeMap();
-        NodeMap<Placeholder> exits = graph.createNodeMap();
-
+        NodeMap<StateSplit> exits = graph.createNodeMap();
+        NodeBitMap unaffectedExits = graph.createNodeBitMap();
+        NodeBitMap clonedExits = graph.createNodeBitMap();
         for (Node exit : loop.exits()) {
             if (marked.isMarked(exit.singlePredecessor())) {
-                Placeholder pExit = (Placeholder) exit;
-                marked.mark(pExit.stateAfter());
-                Placeholder p = new Placeholder(graph);
-                replacements.put(exit, p);
-                exits.set(exit, p);
+                StateSplit pExit = findNearestMergableExitPoint(exit, marked);
+                markWithState(pExit, marked);
+                clonedExits.mark(pExit);
+            } else {
+                unaffectedExits.mark(exit);
             }
         }
 
@@ -587,7 +576,7 @@
                 marked.clear(n);
             }
             for (Node input : n.dataInputs()) {
-                if (!marked.isMarked(input) && (!(input instanceof Phi) || ((Phi) input).merge() != loopBegin)) {
+                if (!marked.isMarked(input) && (!(input instanceof Phi) || ((Phi) input).merge() != loopBegin) && replacements.get(input) == null) {
                     replacements.put(input, input);
                 }
             }
@@ -602,6 +591,10 @@
 
         Map<Node, Node> duplicates = graph.addDuplicate(marked, replacements);
 
+        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()) {
@@ -628,7 +621,12 @@
 
         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);
+        return new PeelingResult(newBegin, newFrom, exits, phis, phiInits, dataOut, unaffectedExits);
+    }
+
+    private static StateSplit findNearestMergableExitPoint(Node exit, NodeBitMap marked) {
+        // TODO (gd) find appropriate point : will be useful if a loop exit goes "up" as a result of making a branch dead in the loop body
+        return (StateSplit) exit;
     }
 
     private static NodeBitMap inOrBefore(Loop loop) {
@@ -686,8 +684,9 @@
         map.mark(n);
         if (n instanceof StateSplit) {
             FrameState stateAfter = ((StateSplit) n).stateAfter();
-            if (stateAfter != null) {
+            while (stateAfter != null) {
                 map.mark(stateAfter);
+                stateAfter = stateAfter.outerFrameState();
             }
         }
     }
@@ -696,8 +695,9 @@
         map.clear(n);
         if (n instanceof StateSplit) {
             FrameState stateAfter = ((StateSplit) n).stateAfter();
-            if (stateAfter != null) {
+            while (stateAfter != null) {
                 map.clear(stateAfter);
+                stateAfter = stateAfter.outerFrameState();
             }
         }
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Fri Jul 01 19:39:29 2011 +0200
@@ -469,15 +469,31 @@
     public void forEachLiveStateValue(ValueProcedure proc) {
         for (int i = 0; i < valuesSize(); i++) {
             Value value = valueAt(i);
-            if (value != null) {
-                proc.doValue(value);
-            }
+            visitLiveStateValue(value, proc);
         }
         if (outerFrameState() != null) {
             outerFrameState().forEachLiveStateValue(proc);
         }
     }
 
+    private void visitLiveStateValue(Value value, ValueProcedure proc) {
+        if (value != null) {
+            if (value instanceof VirtualObject) {
+                HashSet<Object> fields = new HashSet<Object>();
+                VirtualObject obj = (VirtualObject) value;
+                do {
+                    if (!fields.contains(obj.field().representation())) {
+                        fields.add(obj.field().representation());
+                        visitLiveStateValue(obj.input(), proc);
+                    }
+                    obj = obj.object();
+                } while (obj != null);
+            } else {
+                proc.doValue(value);
+            }
+        }
+    }
+
     @Override
     public String toString() {
         return super.toString();
--- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java	Fri Jul 01 19:39:14 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java	Fri Jul 01 19:39:29 2011 +0200
@@ -51,7 +51,7 @@
                 List<Group> children = new ArrayList<Group>();
                 children.add(g);
                 if(g.getGraphs().size() == 1) {
-                    g.getGraphs().get(0).setName(g.getName() + " / " + g.getGraphs().get(0).getName());
+                    //g.getGraphs().get(0).setName(g.getName() + " / " + g.getGraphs().get(0).getName());
                     result.add(new Pair<String, List<Group>>("", children));
                 } else {
                     Pair<String, List<Group>> p = new Pair<String, List<Group>>();