changeset 3128:5cdaa94cd622

Merge.
author Thomas Wuerthinger <thomas@wuerthinger.net>
date Fri, 01 Jul 2011 18:24:04 +0200
parents 0affee9ff3a9 3664989976e2
children acda73820e9b
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java 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 graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/DeadCodeEliminationPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/Bundle.properties src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/layer.xml src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/preferences.xml src/share/tools/IdealGraphVisualizer/Text Editor/build/depcache/dependencies.txt src/share/tools/IdealGraphVisualizer/Text Editor/build/no-license.txt
diffstat 79 files changed, 2873 insertions(+), 666 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalCompiler.java	Fri Jul 01 18:24:04 2011 +0200
@@ -72,7 +72,7 @@
         Graph.verificationListeners.add(new VerificationListener() {
             @Override
             public void verificationFailed(Node n, String message) {
-                GraalCompiler.this.fireCompilationEvent(new CompilationEvent(currentCompilation, "Verification Error on Node " + n.id(), currentCompilation.graph, true, false));
+                GraalCompiler.this.fireCompilationEvent(new CompilationEvent(currentCompilation, "Verification Error on Node " + n.id(), currentCompilation.graph, true, false, true));
                 TTY.println(n.toString());
                 for (Node p : n.predecessors()) {
                     TTY.println("predecessor: " + p);
@@ -146,7 +146,7 @@
         if (GraalOptions.PrintDOTGraphToPdf) {
             addCompilationObserver(new GraphvizPrinterObserver(true));
         }
-        if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot) {
+        if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) {
             CompilationObserver observer;
             if (GraalOptions.PrintIdealGraphFile) {
                 observer = new IdealGraphPrinterObserver();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalOptions.java	Fri Jul 01 18:24:04 2011 +0200
@@ -54,6 +54,11 @@
     public static int     MaximumDesiredSize                 = 8000;
     public static int     MaximumShortLoopSize               = 5;
 
+    // escape analysis settings
+    public static boolean EscapeAnalysis                     = ____;
+    public static int     ForcedInlineEscapeWeight           = 0;
+    public static int     MaximumEscapeAnalysisArrayLength   = 32;
+
     // debugging settings
     public static boolean VerifyPointerMaps                  = ____;
     public static int     MethodEndBreakpointGuards          = 0;
@@ -80,6 +85,7 @@
 
     // Ideal graph visualizer output settings
     public static boolean Plot                               = ____;
+    public static boolean PlotOnError                        = ____;
     public static int     PrintIdealGraphLevel               = 0;
     public static boolean PrintIdealGraphFile                = ____;
     public static String  PrintIdealGraphAddress             = "127.0.0.1";
@@ -101,6 +107,7 @@
     public static boolean TraceAssembler                     = ____;
     public static boolean TraceInlining                      = ____;
     public static boolean TraceDeadCodeElimination           = ____;
+    public static boolean TraceEscapeAnalysis                = ____;
     public static boolean TraceCanonicalizer                 = ____;
     public static boolean TraceMemoryMaps                    = ____;
     public static boolean TraceReadElimination               = ____;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScan.java	Fri Jul 01 18:24:04 2011 +0200
@@ -36,6 +36,7 @@
 import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.compiler.lir.LIRInstruction.*;
 import com.oracle.max.graal.compiler.observer.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.compiler.value.FrameState.*;
@@ -318,7 +319,7 @@
     LIRInstruction instructionForId(int opId) {
         assert isEven(opId) : "opId not even";
         LIRInstruction instr = opIdToInstructionMap[opIdToIndex(opId)];
-        assert instr.id == opId;
+        assert instr.id() == opId;
         return instr;
     }
 
@@ -460,7 +461,7 @@
             // iterate all instructions of the block. skip the first because it is always a label
             for (int j = 1; j < numInst; j++) {
                 LIRInstruction op = instructions.get(j);
-                int opId = op.id;
+                int opId = op.id();
 
                 if (opId == -1) {
                     CiValue resultOperand = op.result();
@@ -568,7 +569,7 @@
             int numInst = instructions.size();
             for (int j = 0; j < numInst; j++) {
                 LIRInstruction op = instructions.get(j);
-                op.id = opId;
+                op.setId(opId);
 
                 opIdToInstructionMap[index] = op;
                 opIdToBlockMap[index] = block;
@@ -616,7 +617,7 @@
                         if (!liveKill.get(operandNum)) {
                             liveGen.set(operandNum);
                             if (GraalOptions.TraceLinearScanLevel >= 4) {
-                                TTY.println("  Setting liveGen for operand %d at instruction %d", operandNum, op.id);
+                                TTY.println("  Setting liveGen for operand %d at instruction %d", operandNum, op.id());
                             }
                         }
                         if (block.loopIndex() >= 0) {
@@ -641,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 " + op.toString(), Util.valueString(value), op.id(), operandNum);
                                     }
                                 }
                             } else if (operand.isRegister()) {
@@ -848,13 +849,13 @@
                     if (block.liveGen.get(operandNum)) {
                         TTY.println("  used in block B%d", block.blockID());
                         for (LIRInstruction ins : block.lir().instructionsList()) {
-                            TTY.println(ins.id + ": " + ins.result() + " " + ins.toString());
+                            TTY.println(ins.id() + ": " + ins.result() + " " + ins.toString());
                         }
                     }
                     if (block.liveKill.get(operandNum)) {
                         TTY.println("  defined in block B%d", block.blockID());
                         for (LIRInstruction ins : block.lir().instructionsList()) {
-                            TTY.println(ins.id + ": " + ins.result() + " " + ins.toString());
+                            TTY.println(ins.id() + ": " + ins.result() + " " + ins.toString());
                         }
                     }
                 }
@@ -1102,8 +1103,8 @@
                 if (GraalOptions.DetailedAsserts) {
                     int argSlots = compilation.method.signature().argumentSlots(!isStatic(compilation.method.accessFlags()));
                     assert slot.index() >= 0 && slot.index() < argSlots;
-                    assert move.id > 0 : "invalid id";
-                    assert blockForId(move.id).numberOfPreds() == 0 : "move from stack must be in first block";
+                    assert move.id() > 0 : "invalid id";
+                    assert blockForId(move.id()).numberOfPreds() == 0 : "move from stack must be in first block";
                     assert move.result().isVariable() : "result of move must be a variable";
 
                     if (GraalOptions.TraceLinearScanLevel >= 4) {
@@ -1137,7 +1138,7 @@
                     if (from != null && to != null) {
                         to.setLocationHint(from);
                         if (GraalOptions.TraceLinearScanLevel >= 4) {
-                            TTY.println("operation at opId %d: added hint from interval %d to %d", move.id, from.operandNumber, to.operandNumber);
+                            TTY.println("operation at opId %d: added hint from interval %d to %d", move.id(), from.operandNumber, to.operandNumber);
                         }
                     }
                 }
@@ -1155,7 +1156,7 @@
                     if (from != null && to != null) {
                         to.setLocationHint(from);
                         if (GraalOptions.TraceLinearScanLevel >= 4) {
-                            TTY.println("operation at opId %d: added hint from interval %d to %d", cmove.id, from.operandNumber, to.operandNumber);
+                            TTY.println("operation at opId %d: added hint from interval %d to %d", cmove.id(), from.operandNumber, to.operandNumber);
                         }
                     }
                 }
@@ -1179,8 +1180,8 @@
             final int blockFrom = block.firstLirInstructionId();
             int blockTo = block.lastLirInstructionId();
 
-            assert blockFrom == instructions.get(0).id;
-            assert blockTo == instructions.get(instructions.size() - 1).id;
+            assert blockFrom == instructions.get(0).id();
+            assert blockTo == instructions.get(instructions.size() - 1).id();
 
             // Update intervals for operands live at the end of this block;
             BitMap live = block.liveOut;
@@ -1208,7 +1209,7 @@
             assert !instructions.get(0).hasOperands() : "first operation must always be a label";
             for (int j = instructions.size() - 1; j >= 1; j--) {
                 LIRInstruction op = instructions.get(j);
-                final int opId = op.id;
+                final int opId = op.id();
 
                 // add a temp range for each register if operation destroys caller-save registers
                 if (op.hasCall) {
@@ -1269,9 +1270,17 @@
                 if (info != null) {
                     info.state.forEachLiveStateValue(new ValueProcedure() {
                         public void doValue(Value value) {
-                            CiValue operand = value.operand();
-                            if (operand.isVariableOrRegister()) {
-                                addUse(operand, blockFrom, (opId + 1), RegisterPriority.None, null);
+                            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);
+                                }
                             }
                         }
                     });
@@ -1315,7 +1324,7 @@
                 if (GraalOptions.TraceLinearScanLevel >= 2) {
                     TTY.println("killing XMMs for trig");
                 }
-                int opId = op.id;
+                int opId = op.id();
 
                 for (CiRegister r : compilation.registerConfig.getCallerSaveRegisters()) {
                     if (r.isFpu()) {
@@ -1770,19 +1779,19 @@
 
     void computeOopMap(IntervalWalker iw, LIRInstruction op, LIRDebugInfo info, boolean isCallSite, BitMap frameRefMap, BitMap regRefMap) {
         if (GraalOptions.TraceLinearScanLevel >= 3) {
-            TTY.println("creating oop map at opId %d", op.id);
+            TTY.println("creating oop map at opId %d", op.id());
         }
 
         // walk before the current operation . intervals that start at
         // the operation (i.e. output operands of the operation) are not
         // included in the oop map
-        iw.walkBefore(op.id);
+        iw.walkBefore(op.id());
 
         // Iterate through active intervals
         for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) {
             CiValue operand = interval.operand;
 
-            assert interval.currentFrom() <= op.id && op.id <= interval.currentTo() : "interval should not be active otherwise";
+            assert interval.currentFrom() <= op.id() && op.id() <= interval.currentTo() : "interval should not be active otherwise";
             assert interval.operand.isVariable() : "fixed interval found";
 
             // Check if this range covers the instruction. Intervals that
@@ -1791,7 +1800,7 @@
             // moves, any intervals which end at this instruction are included
             // in the oop map since we may safepoint while doing the patch
             // before we've consumed the inputs.
-            if (op.id < interval.currentTo()) {
+            if (op.id() < interval.currentTo()) {
                 // caller-save registers must not be included into oop-maps at calls
                 assert !isCallSite || !operand.isRegister() || !isCallerSave(operand) : "interval is in a caller-save register at a call . register will be overwritten";
 
@@ -1803,7 +1812,7 @@
 
                 // Spill optimization: when the stack value is guaranteed to be always correct,
                 // then it must be added to the oop map even if the interval is currently in a register
-                if (interval.alwaysInMemory() && op.id > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) {
+                if (interval.alwaysInMemory() && op.id() > interval.spillDefinitionPos() && !interval.location().equals(interval.spillSlot())) {
                     assert interval.spillDefinitionPos() > 0 : "position not set correctly";
                     assert interval.spillSlot() != null : "no spill slot assigned";
                     assert !interval.operand.isRegister() : "interval is on stack :  so stack slot is registered twice";
@@ -1837,7 +1846,9 @@
     }
 
     CiValue toCiValue(int opId, Value value) {
-        if (value != null && value.operand() != CiValue.IllegalValue) {
+        if (value instanceof VirtualObject) {
+            return toCiVirtualObject(opId, (VirtualObject) value);
+        } else if (value != null && value.operand() != CiValue.IllegalValue) {
             CiValue operand = value.operand();
             Constant con = null;
             if (value instanceof Constant) {
@@ -1884,6 +1895,35 @@
         }
     }
 
+    private CiVirtualObject toCiVirtualObject(int opId, VirtualObject obj) {
+        RiType type = obj.type();
+        EscapeField[] escapeFields = obj.fields();
+        CiValue[] values = new CiValue[escapeFields.length];
+
+        VirtualObject current = obj;
+        do {
+            boolean found = false;
+            for (int i = 0; i < escapeFields.length; i++) {
+                if (escapeFields[i].representation() == current.field().representation()) {
+                    if (values[i] == null) {
+                        values[i] = toCiValue(opId, current.input());
+                    }
+                    found = true;
+                    break;
+                }
+            }
+            assert found : type + "." + current.field() + " not found";
+            current = current.object();
+        } while (current != null);
+
+        for (int i = 0; i < escapeFields.length; i++) {
+            assert values[i] != null : type + "." + escapeFields[i];
+        }
+
+        CiVirtualObject vobj = CiVirtualObject.get(type, values, obj.id());
+        return vobj;
+    }
+
     CiFrame computeFrameForState(FrameState state, int opId, BitMap frameRefMap) {
         CiValue[] values = new CiValue[state.valuesSize() + state.locksSize()];
         int valueIndex = 0;
@@ -1937,11 +1977,11 @@
                 int frameWords = frameSize / compilation.target.spillSlotSize;
                 BitMap frameRefMap = new BitMap(frameWords);
                 BitMap regRefMap = !op.hasCall ? new BitMap(compilation.target.arch.registerReferenceMapBitCount) : null;
-                CiFrame frame = compilation.placeholderState != null ? null : computeFrame(info.state, op.id, frameRefMap);
+                CiFrame frame = compilation.placeholderState != null ? null : computeFrame(info.state, op.id(), frameRefMap);
                 computeOopMap(iw, op, info, frameRefMap, regRefMap);
                 info.debugInfo = new CiDebugInfo(frame, regRefMap, frameRefMap);
             } else if (GraalOptions.DetailedAsserts) {
-                assert info.debugInfo.frame().equals(computeFrame(info.state, op.id, new BitMap(info.debugInfo.frameRefMap.size())));
+                assert info.debugInfo.frame().equals(computeFrame(info.state, op.id(), new BitMap(info.debugInfo.frameRefMap.size())));
             }
         }
     }
@@ -1970,7 +2010,7 @@
                 for (int k = 0; k < n; k++) {
                     CiValue operand = op.operandAt(mode, k);
                     if (operand.isVariable()) {
-                        op.setOperandAt(mode, k, colorLirOperand((CiVariable) operand, op.id, mode));
+                        op.setOperandAt(mode, k, colorLirOperand((CiVariable) operand, op.id(), mode));
                     }
                 }
             }
@@ -2256,14 +2296,14 @@
                 LIRInstruction op = instructions.get(j);
 
                 if (op.info != null) {
-                    iw.walkBefore(op.id);
+                    iw.walkBefore(op.id());
                     boolean checkLive = true;
 
                     // Make sure none of the fixed registers is live across an
                     // oopmap since we can't handle that correctly.
                     if (checkLive) {
                         for (Interval interval = iw.activeLists.get(RegisterBinding.Fixed); interval != Interval.EndMarker; interval = interval.next) {
-                            if (interval.currentTo() > op.id + 1) {
+                            if (interval.currentTo() > op.id() + 1) {
                                 // This interval is live out of this op so make sure
                                 // that this interval represents some value that's
                                 // referenced by this op either as an input or output.
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/LinearScanWalker.java	Fri Jul 01 18:24:04 2011 +0200
@@ -233,15 +233,15 @@
         // When the block already contains spill moves, the index must be increased until the
         // correct index is reached.
         List<LIRInstruction> list = opBlock.lir().instructionsList();
-        int index = (opId - list.get(0).id) >> 1;
-        assert list.get(index).id <= opId : "error in calculation";
+        int index = (opId - list.get(0).id()) >> 1;
+        assert list.get(index).id() <= opId : "error in calculation";
 
-        while (list.get(index).id != opId) {
+        while (list.get(index).id() != opId) {
             index++;
             assert 0 <= index && index < list.size() : "index out of bounds";
         }
         assert 1 <= index && index < list.size() : "index out of bounds";
-        assert list.get(index).id == opId : "error in calculation";
+        assert list.get(index).id() == opId : "error in calculation";
 
         // insert new instruction before instruction at position index
         moveResolver.moveInsertPosition(opBlock.lir(), index - 1);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/alloc/RegisterVerifier.java	Fri Jul 01 18:24:04 2011 +0200
@@ -229,8 +229,8 @@
                 CiValue operand = op.operandAt(LIRInstruction.OperandMode.Input, j);
                 if (allocator.isProcessed(operand)) {
                     Interval interval = intervalAt(operand);
-                    if (op.id != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Input, allocator);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Input, allocator);
                     }
 
                     assert checkState(inputState, interval.location(), interval.splitParent());
@@ -251,8 +251,8 @@
                 if (allocator.isProcessed(operand)) {
                     Interval interval = intervalAt(operand);
                     assert interval != null : "Could not find interval for operand " + operand;
-                    if (op.id != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Temp, allocator);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Temp, allocator);
                     }
 
                     statePut(inputState, interval.location(), interval.splitParent());
@@ -265,8 +265,8 @@
                 CiValue operand = op.operandAt(LIRInstruction.OperandMode.Output, j);
                 if (allocator.isProcessed(operand)) {
                     Interval interval = intervalAt(operand);
-                    if (op.id != -1) {
-                        interval = interval.getSplitChildAtOpId(op.id, LIRInstruction.OperandMode.Output, allocator);
+                    if (op.id() != -1) {
+                        interval = interval.getSplitChildAtOpId(op.id(), LIRInstruction.OperandMode.Output, allocator);
                     }
 
                     statePut(inputState, interval.location(), interval.splitParent());
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java	Fri Jul 01 18:24:04 2011 +0200
@@ -479,7 +479,7 @@
             out.println("LIR");
             for (int i = 0; i < lir.length(); i++) {
                 LIRInstruction inst = lir.at(i);
-                out.printf("nr %4d ", inst.id).print(COLUMN_END);
+                out.printf("nr %4d ", inst.id()).print(COLUMN_END);
 
                 if (inst.info != null) {
                     int level = out.indentationLevel();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Fri Jul 01 18:24:04 2011 +0200
@@ -24,6 +24,7 @@
 
 import java.io.*;
 import java.util.*;
+import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.Map.Entry;
 
 import com.oracle.max.graal.compiler.ir.*;
@@ -109,24 +110,33 @@
         flush();
     }
 
+    public void print(Graph graph, String title, boolean shortNames) {
+        print(graph, title, shortNames, Collections.<String, Object>emptyMap());
+    }
+
     /**
      * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes.
      */
-    public void print(Graph graph, String title, boolean shortNames) {
+    public void print(Graph graph, String title, boolean shortNames, Map<String, Object> debugObjects) {
         stream.printf(" <graph name='%s'>%n", escape(title));
         noBlockNodes.clear();
         IdentifyBlocksPhase schedule = null;
         try {
             schedule = new IdentifyBlocksPhase(true);
-            schedule.apply(graph);
+            schedule.apply(graph, false);
         } catch (Throwable t) {
             // nothing to do here...
+            //t.printStackTrace();
+        }
+        List<Loop> loops = null;
+        try {
+            loops = LoopUtil.computeLoops(graph);
+        } catch (Throwable t) {
             t.printStackTrace();
         }
-        List<Loop> loops = LoopUtil.computeLoops(graph);
 
         stream.println("  <nodes>");
-        List<Edge> edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops);
+        List<Edge> edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops, debugObjects);
         stream.println("  </nodes>");
 
         stream.println("  <edges>");
@@ -148,11 +158,52 @@
         flush();
     }
 
-    private List<Edge> printNodes(Graph graph, boolean shortNames, NodeMap<Block> nodeToBlock, List<Loop> loops) {
+    private List<Edge> printNodes(Graph graph, boolean shortNames, NodeMap<Block> nodeToBlock, List<Loop> loops, Map<String, Object> debugObjects) {
         ArrayList<Edge> edges = new ArrayList<Edge>();
         NodeBitMap loopExits = graph.createNodeBitMap();
-        for (Loop loop : loops) {
-            loopExits.markAll(loop.exist());
+        if (loops != null) {
+            for (Loop loop : loops) {
+                loopExits.setUnion(loop.exits());
+            }
+        }
+
+        Map<Node, Set<Entry<String, Integer>>> colors = new HashMap<Node, Set<Entry<String, Integer>>>();
+        Map<Node, Set<String>> bits = new HashMap<Node, Set<String>>();
+        if (debugObjects != null) {
+            for (Entry<String, Object> entry : debugObjects.entrySet()) {
+                String name = entry.getKey();
+                Object obj = entry.getValue();
+                if (obj instanceof NodeMap) {
+                    Map<Object, Integer> colorNumbers = new HashMap<Object, Integer>();
+                    int nextColor = 0;
+                    NodeMap<?> map = (NodeMap<?>) obj;
+                    for (Entry<Node, ?> mapEntry : map.entries()) {
+                        Node node = mapEntry.getKey();
+                        Object color = mapEntry.getValue();
+                        Integer colorNumber = colorNumbers.get(color);
+                        if (colorNumber == null) {
+                            colorNumber = nextColor++;
+                            colorNumbers.put(color, colorNumber);
+                        }
+                        Set<Entry<String, Integer>> nodeColors = colors.get(node);
+                        if (nodeColors == null) {
+                            nodeColors = new HashSet<Entry<String, Integer>>();
+                            colors.put(node, nodeColors);
+                        }
+                        nodeColors.add(new SimpleImmutableEntry<String, Integer>(name + "Color", colorNumber));
+                    }
+                } else if (obj instanceof NodeBitMap) {
+                    NodeBitMap bitmap = (NodeBitMap) obj;
+                    for (Node node : bitmap) {
+                        Set<String> nodeBits = bits.get(node);
+                        if (nodeBits == null) {
+                            nodeBits = new HashSet<String>();
+                            bits.put(node, nodeBits);
+                        }
+                        nodeBits.add(name);
+                    }
+                }
+            }
         }
 
         for (Node node : graph.getNodes()) {
@@ -188,17 +239,35 @@
                 stream.printf("    <p name='loopExit'>true</p>%n");
             }
             StringBuilder sb = new StringBuilder();
-            for (Loop loop : loops) {
-                if (loop.nodes().isMarked(node)) {
-                    if (sb.length() > 0) {
-                        sb.append(", ");
+            if (loops != null) {
+                for (Loop loop : loops) {
+                    if (loop.nodes().isMarked(node)) {
+                        if (sb.length() > 0) {
+                            sb.append(", ");
+                        }
+                        sb.append(loop.loopBegin().id());
                     }
-                    sb.append(loop.loopBegin().id());
                 }
             }
             if (sb.length() > 0) {
                 stream.printf("    <p name='loops'>%s</p>%n", sb);
             }
+
+            Set<Entry<String, Integer>> nodeColors = colors.get(node);
+            if (nodeColors != null) {
+                for (Entry<String, Integer> color : nodeColors) {
+                    String name = color.getKey();
+                    Integer value = color.getValue();
+                    stream.printf("    <p name='%s'>%d</p>%n", name, value);
+                }
+            }
+            Set<String> nodeBits = bits.get(node);
+            if (nodeBits != null) {
+                for (String bit : nodeBits) {
+                    stream.printf("    <p name='%s'>true</p>%n", bit);
+                }
+            }
+
             for (Entry<Object, Object> entry : props.entrySet()) {
                 String key = entry.getKey().toString();
                 String value = entry.getValue() == null ? "null" : entry.getValue().toString();
@@ -237,11 +306,9 @@
         stream.printf("   <block name='%d'>%n", block.blockID());
         stream.printf("    <successors>%n");
         for (Block sux : block.getSuccessors()) {
-//            if (sux.firstNode() instanceof LoopBegin && block.lastNode() instanceof LoopEnd) { //TODO gd
-//                // Skip back edges.
-//            } else {
+            if (sux != null) {
                 stream.printf("     <successor name='%d'/>%n", sux.blockID());
-//            }
+            }
         }
         stream.printf("    </successors>%n");
         stream.printf("    <nodes>%n");
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Fri Jul 01 18:24:04 2011 +0200
@@ -67,7 +67,7 @@
     public void compilationStarted(CompilationEvent event) {
         assert (stream == null && printer == null);
 
-        if (!TTY.isSuppressed()) {
+        if ((!TTY.isSuppressed() && GraalOptions.Plot) || (GraalOptions.PlotOnError && event.isErrorEvent())) {
             String name = event.getMethod().holder().name();
             name = name.substring(1, name.length() - 1).replace('/', '.');
             name = name + "." + event.getMethod().name();
@@ -140,9 +140,17 @@
 
     @Override
     public void compilationEvent(CompilationEvent event) {
+        boolean lazyStart = false;
+        if (printer == null && event.isErrorEvent()) {
+            this.compilationStarted(event);
+            lazyStart = true;
+        }
         if (printer != null && event.getGraph() != null && event.isHIRValid()) {
             Graph graph = event.getGraph();
-            printer.print(graph, event.getLabel(), true);
+            printer.print(graph, event.getLabel(), true, event.getDebugObjects());
+        }
+        if (lazyStart) {
+            this.compilationFinished(event);
         }
     }
 
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Fri Jul 01 18:24:04 2011 +0200
@@ -395,7 +395,7 @@
     @Override
     public void visitNewObjectArray(NewObjectArray x) {
         XirArgument length = toXirArgument(x.length());
-        XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementClass(), x.exactType());
+        XirSnippet snippet = xir.genNewArray(site(x), length, CiKind.Object, x.elementType(), x.exactType());
         emitXir(snippet, x, stateFor(x), null, true);
     }
 
@@ -1074,7 +1074,7 @@
             lastState = fs;
         } else if (block.blockPredecessors().size() == 1) {
             FrameState fs = block.blockPredecessors().get(0).lastState();
-            assert fs != null; //TODO gd maybe this assert should be removed
+            assert fs != null;
             if (GraalOptions.TraceLIRGeneratorLevel >= 2) {
                 TTY.println("STATE CHANGE (singlePred)");
                 if (GraalOptions.TraceLIRGeneratorLevel >= 3) {
@@ -1485,6 +1485,9 @@
     }
 
     private void moveToPhi(Merge merge, Node pred) {
+        if (GraalOptions.TraceLIRGeneratorLevel >= 1) {
+            TTY.println("MOVE TO PHI from " + pred + " to " + merge);
+        }
         int nextSuccIndex = merge.phiPredecessorIndex(pred);
         PhiResolver resolver = new PhiResolver(this);
         for (Phi phi : merge.phis()) {
@@ -1628,7 +1631,9 @@
 
     private void walkStateValue(Value value) {
         if (value != null) {
-            if (value instanceof Phi && !((Phi) value).isDead()) {
+            if (value instanceof VirtualObject) {
+                walkVirtualObject((VirtualObject) value);
+            } else if (value instanceof Phi && !((Phi) value).isDead()) {
                 // phi's are special
                 operandForPhi((Phi) value);
             } else if (value.operand().isIllegal()) {
@@ -1639,6 +1644,13 @@
         }
     }
 
+    private void walkVirtualObject(VirtualObject value) {
+        walkStateValue(value.input());
+        if (value.object() != null) {
+            walkVirtualObject(value.object());
+        }
+    }
+
     protected LIRDebugInfo stateFor(Value x) {
         assert lastState != null : "must have state before instruction for " + x;
         return stateFor(x, lastState);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graph/IR.java	Fri Jul 01 18:24:04 2011 +0200
@@ -90,7 +90,7 @@
         //printGraph("After DeadCodeElimination", compilation.graph);
 
         if (GraalOptions.Inline) {
-            new InliningPhase(compilation, this, GraalOptions.TraceInlining).apply(compilation.graph);
+            new InliningPhase(compilation, this, null).apply(compilation.graph);
         }
 
         Graph graph = compilation.graph;
@@ -100,6 +100,13 @@
             new DeadCodeEliminationPhase().apply(graph);
         }
 
+        if (GraalOptions.EscapeAnalysis) {
+            new EscapeAnalysisPhase(compilation, this).apply(graph);
+            new DeadCodeEliminationPhase().apply(graph);
+            new CanonicalizerPhase().apply(graph);
+            new DeadCodeEliminationPhase().apply(graph);
+        }
+
         if (GraalOptions.OptGVN) {
             new GlobalValueNumberingPhase().apply(graph);
         }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/EndNode.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/EndNode.java	Fri Jul 01 18:24:04 2011 +0200
@@ -22,6 +22,8 @@
  */
 package com.oracle.max.graal.compiler.ir;
 
+import java.util.*;
+
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
@@ -67,4 +69,9 @@
         assertTrue(predecessors().size() <= 1, "at most one predecessor");
         return true;
     }
+
+    @Override
+    public Iterable< ? extends Node> dataUsages() {
+        return Collections.emptyList();
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/ExceptionObject.java	Fri Jul 01 18:24:04 2011 +0200
@@ -29,9 +29,10 @@
 /**
  * The {@code ExceptionObject} instruction represents the incoming exception object to an exception handler.
  */
-public final class ExceptionObject extends FixedNodeWithNext {
+public final class ExceptionObject extends StateSplit {
 
     private static final int INPUT_COUNT = 0;
+
     private static final int SUCCESSOR_COUNT = 0;
 
     /**
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Invoke.java	Fri Jul 01 18:24:04 2011 +0200
@@ -84,7 +84,6 @@
     public final RiMethod target;
     public final RiType returnType;
     public final int bci; // XXX needed because we can not compute the bci from the sateBefore bci of this Invoke was optimized from INVOKEINTERFACE to INVOKESPECIAL
-    public final RiTypeProfile profile;
 
     /**
      * Constructs a new Invoke instruction.
@@ -95,13 +94,12 @@
      * @param isStatic {@code true} if this call is static (no receiver object)
      * @param target the target method being called
      */
-    public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, RiTypeProfile profile, Graph graph) {
+    public Invoke(int bci, int opcode, CiKind result, Value[] args, RiMethod target, RiType returnType, Graph graph) {
         super(result, args.length, SUCCESSOR_COUNT, graph);
         this.opcode = opcode;
         this.target = target;
         this.returnType = returnType;
         this.bci = bci;
-        this.profile = profile;
 
         this.argumentCount = args.length;
         for (int i = 0; i < args.length; i++) {
@@ -148,10 +146,6 @@
         return target;
     }
 
-    public RiTypeProfile profile() {
-        return profile;
-    }
-
     /**
      * Checks whether this invocation has a receiver object.
      * @return {@code true} if this invocation has a receiver object; {@code false} otherwise, if this is a
@@ -201,7 +195,7 @@
 
     @Override
     public Node copy(Graph into) {
-        Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, profile, into);
+        Invoke x = new Invoke(bci, opcode, kind, new Value[argumentCount], target, returnType, into);
         return x;
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/LoopBegin.java	Fri Jul 01 18:24:04 2011 +0200
@@ -28,10 +28,9 @@
 import com.oracle.max.graal.compiler.util.*;
 import com.oracle.max.graal.graph.*;
 
-public class LoopBegin extends Merge{
+public class LoopBegin extends Merge {
     public LoopBegin(Graph graph) {
         super(graph);
-        this.addEnd(new EndNode(graph));
     }
 
     public LoopEnd loopEnd() {
@@ -81,6 +80,16 @@
         throw Util.shouldNotReachHere("unknown pred : " + pred + "(sp=" + forwardEdge() + ", le=" + this.loopEnd() + ")");
     }
 
+    @Override
+    public Node phiPredecessorAt(int index) {
+        if (index == 0) {
+            return forwardEdge();
+        } else if (index == 1) {
+            return loopEnd();
+        }
+        throw Util.shouldNotReachHere();
+    }
+
     public Collection<LoopCounter> counters() {
         return Util.filter(this.usages(), LoopCounter.class);
     }
@@ -107,6 +116,12 @@
     }
 
     @Override
+    public Node singlePredecessor() {
+        assert endCount() == 1;
+        return endAt(0).singlePredecessor();
+    }
+
+    @Override
     public Iterable< ? extends Node> dataUsages() {
         final Iterator< ? extends Node> dataUsages = super.dataUsages().iterator();
         return new Iterable<Node>() {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Merge.java	Fri Jul 01 18:24:04 2011 +0200
@@ -337,6 +337,10 @@
         return endIndex(end);
     }
 
+    public Node phiPredecessorAt(int index) {
+        return endAt(index);
+    }
+
     public Collection<Phi> phis() {
         return Util.filter(this.usages(), Phi.class);
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewArray.java	Fri Jul 01 18:24:04 2011 +0200
@@ -22,6 +22,12 @@
  */
 package com.oracle.max.graal.compiler.ir;
 
+import java.util.*;
+
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp;
+import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 
@@ -30,6 +36,8 @@
  */
 public abstract class NewArray extends FixedNodeWithNext {
 
+    private static final EscapeOp ESCAPE = new NewArrayEscapeOp();
+
     private static final int INPUT_COUNT = 1;
     private static final int INPUT_LENGTH = 0;
 
@@ -67,4 +75,154 @@
         super(CiKind.Object, inputCount + INPUT_COUNT, successorCount + SUCCESSOR_COUNT, graph);
         setLength(length);
     }
+
+    /**
+     * The list of instructions which produce input for this instruction.
+     */
+    public Value dimension(int index) {
+        assert index == 0;
+        return length();
+    }
+
+    /**
+     * The rank of the array allocated by this instruction, i.e. how many array dimensions.
+     */
+    public int dimensionCount() {
+        return 1;
+    }
+
+    public abstract CiKind elementKind();
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == EscapeOp.class) {
+            return (T) ESCAPE;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static class NewArrayEscapeOp implements EscapeOp {
+
+        @Override
+        public boolean canAnalyze(Node node) {
+            NewArray x = (NewArray) node;
+            CiConstant length = x.dimension(0).asConstant();
+            return length != null && length.asInt() >= 0 && length.asInt() < GraalOptions.MaximumEscapeAnalysisArrayLength;
+        }
+
+        @Override
+        public boolean escape(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof FrameState) {
+                FrameState x = (FrameState) usage;
+                assert x.inputs().contains(node);
+                return true;
+            } else if (usage instanceof LoadIndexed) {
+                LoadIndexed x = (LoadIndexed) usage;
+                assert x.array() == node;
+                CiConstant index = x.index().asConstant();
+                CiConstant length = ((NewArray) node).dimension(0).asConstant();
+                if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) {
+                    return true;
+                }
+                return false;
+            } else if (usage instanceof StoreField) {
+                StoreField x = (StoreField) usage;
+                assert x.value() == node;
+                return true;
+            } else if (usage instanceof StoreIndexed) {
+                StoreIndexed x = (StoreIndexed) usage;
+                CiConstant index = x.index().asConstant();
+                CiConstant length = ((NewArray) node).dimension(0).asConstant();
+                if (index == null || length == null || index.asInt() < 0 || index.asInt() >= length.asInt()) {
+                    return true;
+                }
+                return x.value() == node;
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof ArrayLength) {
+                ArrayLength x = (ArrayLength) usage;
+                assert x.array() == node;
+                return false;
+            } else if (usage instanceof VirtualObject) {
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        @Override
+        public EscapeField[] fields(Node node) {
+            NewArray x = (NewArray) node;
+            int length = x.dimension(0).asConstant().asInt();
+            EscapeField[] fields = new EscapeField[length];
+            for (int i = 0; i < length; i++) {
+                Integer representation = i;
+                fields[i] = new EscapeField("[" + i + "]", representation, ((NewArray) node).elementKind());
+            }
+            return fields;
+        }
+
+        @Override
+        public void beforeUpdate(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replaceAndDelete(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.type() == ((NewArray) node).exactType();
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replaceAndDelete(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                x.replaceAndDelete(x.next());
+            } else if (usage instanceof ArrayLength) {
+                ArrayLength x = (ArrayLength) usage;
+                x.replaceAndDelete(((NewArray) node).dimension(0));
+            }
+        }
+
+        @Override
+        public void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState) {
+            if (current instanceof AccessIndexed) {
+                int index = ((AccessIndexed) current).index().asConstant().asInt();
+                EscapeField field = fields.get(index);
+                if (current instanceof LoadIndexed) {
+                    LoadIndexed x = (LoadIndexed) current;
+                    if (x.array() == node) {
+                        for (Node usage : new ArrayList<Node>(x.usages())) {
+                            assert fieldState.get(field) != null;
+                            usage.inputs().replace(x, fieldState.get(field));
+                        }
+                        assert x.usages().size() == 0;
+                        x.replaceAndDelete(x.next());
+                    }
+                } else if (current instanceof StoreIndexed) {
+                    StoreIndexed x = (StoreIndexed) current;
+                    if (x.array() == node) {
+                        fieldState.put(field, x.value());
+                        assert x.usages().size() == 0;
+                        x.replaceAndDelete(x.next());
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewInstance.java	Fri Jul 01 18:24:04 2011 +0200
@@ -22,7 +22,12 @@
  */
 package com.oracle.max.graal.compiler.ir;
 
+import java.util.*;
+
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeOp;
+import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -30,7 +35,8 @@
 /**
  * The {@code NewInstance} instruction represents the allocation of an instance class object.
  */
-public final class NewInstance extends FloatingNode {
+public final class NewInstance extends FixedNodeWithNext {
+    private static final EscapeOp ESCAPE = new NewInstanceEscapeOp();
 
     private static final int INPUT_COUNT = 0;
     private static final int SUCCESSOR_COUNT = 0;
@@ -85,4 +91,124 @@
         NewInstance x = new NewInstance(instanceClass, cpi, constantPool, into);
         return x;
     }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Op> T lookup(Class<T> clazz) {
+        if (clazz == EscapeOp.class) {
+            return (T) ESCAPE;
+        }
+        return super.lookup(clazz);
+    }
+
+    private static class NewInstanceEscapeOp implements EscapeOp {
+
+        @Override
+        public boolean canAnalyze(Node node) {
+            return ((NewInstance) node).instanceClass().isResolved();
+        }
+
+        @Override
+        public boolean escape(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof FrameState) {
+                FrameState x = (FrameState) usage;
+                assert x.inputs().contains(node);
+                return true;
+            } else if (usage instanceof LoadField) {
+                LoadField x = (LoadField) usage;
+                assert x.object() == node;
+                return x.field().isResolved() == false;
+            } else if (usage instanceof StoreField) {
+                StoreField x = (StoreField) usage;
+                return x.value() == node;
+            } else if (usage instanceof StoreIndexed) {
+                StoreIndexed x = (StoreIndexed) usage;
+                assert x.value() == node;
+                return true;
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                assert x.object() == node;
+                return false;
+            } else if (usage instanceof VirtualObject) {
+                return false;
+            } else if (usage instanceof RegisterFinalizer) {
+                RegisterFinalizer x = (RegisterFinalizer) usage;
+                assert x.object() == node;
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        @Override
+        public EscapeField[] fields(Node node) {
+            NewInstance x = (NewInstance) node;
+            RiField[] riFields = x.instanceClass().fields();
+            EscapeField[] fields = new EscapeField[riFields.length];
+            for (int i = 0; i < riFields.length; i++) {
+                RiField field = riFields[i];
+                fields[i] = new EscapeField(field.name(), field, field.kind().stackKind());
+            }
+            return fields;
+        }
+
+        @Override
+        public void beforeUpdate(Node node, Node usage) {
+            if (usage instanceof IsNonNull) {
+                IsNonNull x = (IsNonNull) usage;
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replaceAndDelete(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof IsType) {
+                IsType x = (IsType) usage;
+                assert x.type() == ((NewInstance) node).instanceClass();
+                if (x.usages().size() == 1 && x.usages().get(0) instanceof FixedGuard) {
+                    FixedGuard guard = (FixedGuard) x.usages().get(0);
+                    guard.replaceAndDelete(guard.next());
+                }
+                x.delete();
+            } else if (usage instanceof AccessMonitor) {
+                AccessMonitor x = (AccessMonitor) usage;
+                x.replaceAndDelete(x.next());
+            } else if (usage instanceof RegisterFinalizer) {
+                RegisterFinalizer x = (RegisterFinalizer) usage;
+                x.replaceAndDelete(x.next());
+            }
+        }
+
+        @Override
+        public void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState) {
+            if (current instanceof AccessField) {
+                EscapeField field = fields.get(((AccessField) current).field());
+                if (current instanceof LoadField) {
+                    LoadField x = (LoadField) current;
+                    if (x.object() == node) {
+                        assert fieldState.get(field) != null : field + ", " + ((AccessField) current).field() + ((AccessField) current).field().hashCode();
+                        for (Node usage : new ArrayList<Node>(x.usages())) {
+                            usage.inputs().replace(x, fieldState.get(field));
+                        }
+                        assert x.usages().size() == 0;
+                        x.replaceAndDelete(x.next());
+                    }
+                } else if (current instanceof StoreField) {
+                    StoreField x = (StoreField) current;
+                    if (x.object() == node) {
+                        fieldState.put(field, x.value());
+                        assert x.usages().size() == 0;
+                        x.replaceAndDelete(x.next());
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewMultiArray.java	Fri Jul 01 18:24:04 2011 +0200
@@ -50,6 +50,7 @@
     /**
      * The list of instructions which produce input for this instruction.
      */
+    @Override
     public Value dimension(int index) {
         assert index >= 0 && index < dimensionCount;
         return (Value) inputs().get(super.inputCount() + index);
@@ -63,6 +64,7 @@
     /**
      * The rank of the array allocated by this instruction, i.e. how many array dimensions.
      */
+    @Override
     public int dimensionCount() {
         return dimensionCount;
     }
@@ -105,6 +107,21 @@
     }
 
     @Override
+    public CiKind elementKind() {
+        return elementType.kind();
+    }
+
+    @Override
+    public RiType exactType() {
+        return elementType.arrayOf();
+    }
+
+    @Override
+    public RiType declaredType() {
+        return exactType();
+    }
+
+    @Override
     public void print(LogStream out) {
         out.print("new multi array [");
         for (int i = 0; i < dimensionCount; i++) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewObjectArray.java	Fri Jul 01 18:24:04 2011 +0200
@@ -52,11 +52,16 @@
      * Gets the type of the elements of the array.
      * @return the element type of the array
      */
-    public RiType elementClass() {
+    public RiType elementType() {
         return elementClass;
     }
 
     @Override
+    public CiKind elementKind() {
+        return elementClass.kind();
+    }
+
+    @Override
     public RiType exactType() {
         return elementClass.arrayOf();
     }
@@ -73,7 +78,7 @@
 
     @Override
     public void print(LogStream out) {
-        out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementClass()));
+        out.print("new object array [").print(length()).print("] ").print(CiUtil.toJavaName(elementType()));
     }
 
     @Override
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/NewTypeArray.java	Fri Jul 01 18:24:04 2011 +0200
@@ -42,6 +42,7 @@
         this.elementType = elementType;
     }
 
+    @Override
     public CiKind elementKind() {
         return elementType.kind();
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Phi.java	Fri Jul 01 18:24:04 2011 +0200
@@ -22,7 +22,10 @@
  */
 package com.oracle.max.graal.compiler.ir;
 
+import java.util.*;
+
 import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.ir.StateSplit.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 
@@ -59,6 +62,7 @@
     }
 
     public void setMerge(Merge n) {
+        assert n != null;
         inputs().set(super.inputCount() + INPUT_MERGE, n);
     }
 
@@ -139,7 +143,11 @@
             }
             str.append(valueAt(i) == null ? "-" : valueAt(i).id());
         }
-        return "Phi: (" + str + ")";
+        if (isDead()) {
+            return "Phi: dead (" + str + ")";
+        } else {
+            return "Phi: (" + str + ")";
+        }
     }
 
     public void addInput(Node y) {
@@ -156,4 +164,16 @@
         x.isDead = isDead;
         return x;
     }
+
+    @Override
+    public Iterable<? extends Node> dataInputs() {
+        final Iterator< ? extends Node> input = super.dataInputs().iterator();
+        return new Iterable<Node>() {
+            @Override
+            public Iterator<Node> iterator() {
+                // TODO Auto-generated method stub
+                return new FilteringIterator(input, Merge.class);
+            }
+        };
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/Value.java	Fri Jul 01 18:24:04 2011 +0200
@@ -26,7 +26,6 @@
 
 import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.gen.*;
-import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
@@ -179,7 +178,7 @@
         return properties;
     }
 
-    @Override
+    /*@Override
     public Iterable<? extends Node> dataUsages() {
         final Iterator<? extends Node> dataUsages = super.dataUsages().iterator();
         return new Iterable<Node>() {
@@ -188,5 +187,5 @@
                 return new StateSplit.FilteringIterator(dataUsages, FrameState.class);
             }
         };
-    }
+    }*/
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/ir/VirtualObject.java	Fri Jul 01 18:24:04 2011 +0200
@@ -0,0 +1,132 @@
+/*
+ * 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.max.graal.compiler.ir;
+
+import java.util.*;
+
+import com.oracle.max.graal.compiler.debug.*;
+import com.oracle.max.graal.compiler.phases.EscapeAnalysisPhase.EscapeField;
+import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
+
+
+public class VirtualObject extends FloatingNode {
+
+    private static final int INPUT_COUNT = 2;
+    private static final int INPUT_OBJECT = 0;
+    private static final int INPUT_INPUT = 1;
+
+    private static final int SUCCESSOR_COUNT = 0;
+
+    @Override
+    protected int inputCount() {
+        return super.inputCount() + INPUT_COUNT;
+    }
+
+    @Override
+    protected int successorCount() {
+        return super.successorCount() + SUCCESSOR_COUNT;
+    }
+
+    /**
+     * The instruction that specifies the old state of the virtual object.
+     */
+     public VirtualObject object() {
+        return (VirtualObject) inputs().get(super.inputCount() + INPUT_OBJECT);
+    }
+
+    private VirtualObject setObject(VirtualObject n) {
+        return (VirtualObject) inputs().set(super.inputCount() + INPUT_OBJECT, n);
+    }
+
+    /**
+     * The instruction that contains the new state of the specified field.
+     */
+     public Value input() {
+        return (Value) inputs().get(super.inputCount() + INPUT_INPUT);
+    }
+
+    public Value setInput(Value n) {
+        return (Value) inputs().set(super.inputCount() + INPUT_INPUT, n);
+    }
+
+    private EscapeField field;
+    private EscapeField[] fields;
+    private RiType type;
+
+    /**
+     * Constructs a new ArrayLength instruction.
+     * @param array the instruction producing the array
+     * @param newFrameState the state after executing this instruction
+     */
+    public VirtualObject(VirtualObject object, Value input, EscapeField field, RiType type, EscapeField[] fields, Graph graph) {
+        super(CiKind.Int, INPUT_COUNT, SUCCESSOR_COUNT, graph);
+        this.field = field;
+        this.type = type;
+        this.fields = fields;
+        setObject(object);
+        setInput(input);
+    }
+
+    public EscapeField field() {
+        return field;
+    }
+
+    public RiType type() {
+        return type;
+    }
+
+    public EscapeField[] fields() {
+        return fields;
+    }
+
+    @Override
+    public void accept(ValueVisitor v) {
+        // nothing to do...
+    }
+
+    @Override
+    public Map<Object, Object> getDebugProperties() {
+        Map<Object, Object> properties = super.getDebugProperties();
+        properties.put("type", type);
+        properties.put("field", field);
+        return properties;
+    }
+
+    @Override
+    public String shortName() {
+        return "VirtualObject " + field.name();
+    }
+
+    @Override
+    public void print(LogStream out) {
+        out.print(object()).print(".").print(field.name()).print("=").print(input());
+    }
+
+    @Override
+    public Node copy(Graph into) {
+        VirtualObject x = new VirtualObject(null, null, field, type, fields, into);
+        return x;
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/lir/LIRInstruction.java	Fri Jul 01 18:24:04 2011 +0200
@@ -90,7 +90,7 @@
     /**
      * Value id for register allocation.
      */
-    public int id;
+    private int id;
 
     /**
      * Determines if all caller-saved registers are destroyed by this instruction.
@@ -198,6 +198,14 @@
         assert verifyOperands();
     }
 
+    public final int id() {
+        return id;
+    }
+
+    public final void setId(int id) {
+        this.id = id;
+    }
+
     private LIROperand initOutput(CiValue output) {
         assert output != null;
         if (output != CiValue.IllegalValue) {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/observer/CompilationEvent.java	Fri Jul 01 18:24:04 2011 +0200
@@ -52,6 +52,8 @@
     private CiTargetMethod targetMethod;
     private boolean hirValid = false;
     private boolean lirValid = false;
+    private boolean errorEvent;
+    private Map<String, Object> debugObjects;
 
     private Interval[] intervals;
     private int intervalsSize;
@@ -68,10 +70,23 @@
     }
 
     public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid) {
+        this(compilation, label, graph, hirValid, lirValid, false, (Map<String, Object>) null);
+    }
+    public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, boolean error) {
+        this(compilation, label, graph, hirValid, lirValid, error, (Map<String, Object>) null);
+    }
+
+    public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, Map<String, Object> debugObjects) {
+        this(compilation, label, graph, hirValid, lirValid, false, debugObjects);
+    }
+
+    public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, boolean error, Map<String, Object> debugObjects) {
         this(compilation, label);
         this.graph = graph;
         this.hirValid = hirValid;
         this.lirValid = lirValid;
+        this.debugObjects = debugObjects;
+        this.errorEvent = error;
     }
 
     public CompilationEvent(GraalCompilation compilation, String label, Graph graph, boolean hirValid, boolean lirValid, CiTargetMethod targetMethod) {
@@ -128,6 +143,10 @@
         return lirValid;
     }
 
+    public boolean isErrorEvent() {
+        return errorEvent;
+    }
+
     public Interval[] getIntervals() {
         if (intervalsCopy == null && intervals != null) {
             // deferred copy of the valid range of the intervals array
@@ -139,4 +158,9 @@
     public int getCodeSize() {
         return codeSize;
     }
+
+
+    public Map<String, Object> getDebugObjects() {
+        return debugObjects;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/EscapeAnalysisPhase.java	Fri Jul 01 18:24:04 2011 +0200
@@ -0,0 +1,387 @@
+/*
+ * 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.max.graal.compiler.phases;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.debug.*;
+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.schedule.*;
+import com.oracle.max.graal.compiler.value.*;
+import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
+import com.sun.cri.ri.*;
+
+
+public class EscapeAnalysisPhase extends Phase {
+
+
+    public static class BlockExitState {
+        public final Map<EscapeField, Node> fieldState;
+        public VirtualObject obj;
+
+        public BlockExitState() {
+            this.fieldState = new HashMap<EscapeField, Node>();
+        }
+    }
+
+    public class EscapementFixup {
+
+        private List<Block> blocks;
+        private final Map<Object, EscapeField> fields = new HashMap<Object, EscapeField>();
+        private final Map<Block, BlockExitState> exitStates = new HashMap<Block, BlockExitState>();
+
+        private final EscapeOp op;
+        private Graph graph;
+        private final Node node;
+        private RiType type;
+        private EscapeField[] escapeFields;
+
+        public EscapementFixup(EscapeOp op, Graph graph, Node node) {
+            this.op = op;
+            this.graph = graph;
+            this.node = node;
+        }
+
+        public void apply() {
+            process();
+            removeAllocation();
+        }
+
+        public void removeAllocation() {
+            final IdentifyBlocksPhase identifyBlocksPhase = new IdentifyBlocksPhase(true);
+            identifyBlocksPhase.apply(graph);
+            blocks = identifyBlocksPhase.getBlocks();
+
+            final HashMap<Phi, EscapeField> phis = new HashMap<Phi, EscapeField>();
+            final Block startBlock = identifyBlocksPhase.getNodeToBlock().get(node);
+            assert startBlock != null;
+            type = ((Value) node).exactType();
+            escapeFields = op.fields(node);
+            for (EscapeField field : escapeFields) {
+                fields.put(field.representation(), field);
+            }
+
+            Block.iteratePostOrder(blocks, new BlockClosure() {
+
+                public void apply(Block block) {
+                    if (GraalOptions.TraceEscapeAnalysis) {
+                        TTY.println("Block %d", block.blockID());
+                    }
+//                    for (Node n : block.getInstructions()) {
+//                        TTY.println("  %d %s", n.id(), n.shortName());
+//                    }
+//                    for (Block b : block.getSuccessors()) {
+//                        TTY.print(" %d", b.blockID());
+//                    }
+//                    TTY.println();
+
+                    BlockExitState state = new BlockExitState();
+                    if (block == startBlock) {
+                        state.obj = null;
+                        for (EscapeField field : fields.values()) {
+                            Constant value = Constant.defaultForKind(field.kind(), graph);
+                            state.fieldState.put(field, value);
+                            state.obj = new VirtualObject(state.obj, value, field, type, escapeFields, graph);
+                        }
+                    } else {
+                        List<Block> predecessors = block.getPredecessors();
+                        Set<EscapeField> mergedFields = new HashSet<EscapeField>();
+
+                        BlockExitState predState = exitStates.get(predecessors.get(0));
+                        state.obj = predState == null ? null : predState.obj;
+
+                        for (int i = 0; i < predecessors.size(); i++) {
+                            BlockExitState exitState = exitStates.get(predecessors.get(i));
+                            if (exitState == null) {
+                                mergedFields.addAll(fields.values());
+                                state.obj = null;
+                                break;
+                            } else {
+                                for (EscapeField field : fields.values()) {
+                                    if (state.fieldState.get(field) == null) {
+                                        state.fieldState.put(field, exitState.fieldState.get(field));
+                                    } else if (state.fieldState.get(field) != exitState.fieldState.get(field)) {
+                                        mergedFields.add(field);
+                                    }
+                                }
+                            }
+                        }
+                        if (!mergedFields.isEmpty()) {
+                            assert block.firstNode() instanceof Merge : "unexpected: " + block.firstNode().shortName() + " " + block.firstNode().id();
+                            for (EscapeField field : mergedFields) {
+                                Phi phi = new Phi(field.kind().stackKind(), (Merge) block.firstNode(), graph);
+                                state.fieldState.put(field, phi);
+                                phis.put(phi, field);
+                                state.obj = new VirtualObject(state.obj, phi, field, type, escapeFields, graph);
+                            }
+                        }
+                    }
+
+                    Node current;
+                    if (block.firstNode() instanceof StartNode) {
+                        current = ((StartNode) block.firstNode()).start();
+                    } else {
+                        current = block.firstNode();
+                    }
+                    while (current != block.lastNode()) {
+                        Node next = ((FixedNodeWithNext) current).next();
+                        op.updateState(node, current, fields, state.fieldState);
+                        if (!current.isDeleted() && current instanceof StateSplit) {
+                            FrameState stateAfter = ((StateSplit) current).stateAfter();
+                            if (stateAfter != null) {
+                                updateFrameState(stateAfter, state.obj);
+                            }
+                        }
+                        current = next;
+                    }
+
+                    if (GraalOptions.TraceEscapeAnalysis) {
+                        TTY.print(" block end state: ");
+                        for (Entry<EscapeField, Node> 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();
+                EscapeField field = entry.getValue();
+                Block block = identifyBlocksPhase.getNodeToBlock().get(entry.getKey().merge());
+
+                List<Block> predecessors = block.getPredecessors();
+                assert predecessors.size() > 0;
+                Node simple = exitStates.get(predecessors.get(0)).fieldState.get(field);
+                for (int i = 1; i < predecessors.size(); i++) {
+                    BlockExitState exitState = exitStates.get(predecessors.get(i));
+                    if (exitState.fieldState.get(field) != simple) {
+                        simple = null;
+                    }
+                }
+                if (simple != null) {
+                    for (Node usage : new ArrayList<Node>(phi.usages())) {
+                        usage.inputs().replace(phi, simple);
+                    }
+                    phi.delete();
+                } else {
+                    for (int i = 0; i < predecessors.size(); i++) {
+                        BlockExitState exitState = exitStates.get(predecessors.get(i));
+                        assert exitState != null;
+                        Node value = exitState.fieldState.get(field);
+                        if (GraalOptions.TraceEscapeAnalysis) {
+                            TTY.println("fixing phi %d with %s", phi.id(), value);
+                        }
+                        if (value == null) {
+                            phi.addInput(Constant.defaultForKind(field.kind(), graph));
+                        } else {
+                            phi.addInput(value);
+                        }
+                    }
+                }
+            }
+            // 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;
+                usage.inputs().replace(node, Node.Null);
+            }
+
+            if (node instanceof FixedNodeWithNext) {
+                node.replaceAndDelete(((FixedNodeWithNext) node).next());
+            } else {
+                node.delete();
+            }
+        }
+
+        private VirtualObject updateFrameState(FrameState frameState, VirtualObject current) {
+            for (int i = 0; i < frameState.inputs().size(); i++) {
+                if (frameState.inputs().get(i) == node) {
+                    frameState.inputs().set(i, current);
+                } else if (frameState.inputs().get(i) instanceof VirtualObject) {
+                    VirtualObject obj = (VirtualObject) frameState.inputs().get(i);
+                    do {
+                        current = updateVirtualObject(obj, current);
+                        obj = obj.object();
+                    } while (obj != null);
+                }
+            }
+            if (frameState.outerFrameState() != null) {
+                current = updateFrameState(frameState.outerFrameState(), current);
+            }
+            return current;
+        }
+
+        private VirtualObject updateVirtualObject(VirtualObject obj, VirtualObject current) {
+            if (obj.input() == node) {
+                obj.setInput(current);
+            } else if (obj.input() instanceof VirtualObject) {
+                VirtualObject obj2 = (VirtualObject) obj.input();
+                do {
+                    current = updateVirtualObject(obj2, current);
+                    obj2 = obj2.object();
+                } while (obj2 != null);
+            }
+            return current;
+        }
+
+        private void process() {
+            for (Node usage : new ArrayList<Node>(node.usages())) {
+                op.beforeUpdate(node, usage);
+            }
+        }
+    }
+
+    private final GraalCompilation compilation;
+    private final IR ir;
+
+    public EscapeAnalysisPhase(GraalCompilation compilation, IR ir) {
+        this.compilation = compilation;
+        this.ir = ir;
+    }
+
+    @Override
+    protected void run(Graph graph) {
+//        if (!compilation.method.holder().name().contains("jnt")) {
+//            return;
+//        }
+//        if (true) return;
+        for (Node node : graph.getNodes()) {
+            EscapeOp op = node.lookup(EscapeOp.class);
+            if (op != null && op.canAnalyze(node)) {
+                Set<Node> exits = new HashSet<Node>();
+                Set<Invoke> invokes = new HashSet<Invoke>();
+                int iterations = 0;
+
+                int weight;
+                int minimumWeight = GraalOptions.ForcedInlineEscapeWeight;
+                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());
+                            }
+                            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);
+                        }
+                        new EscapementFixup(op, graph, node).apply();
+                        new PhiSimplifier(graph);
+                        break;
+                    }
+                    if (weight < minimumWeight) {
+                        if (GraalOptions.TraceEscapeAnalysis) {
+                            TTY.println("####### possibly escaping object: %d in %s (insufficient weight for inlining)", node.id(), compilation.method);
+                        }
+                        break;
+                    }
+                    new InliningPhase(compilation, ir, invokes).apply(graph);
+                    new DeadCodeEliminationPhase().apply(graph);
+                    exits.clear();
+                    invokes.clear();
+                } while (iterations++ < 3);
+            }
+        }
+    }
+
+    private int analyze(EscapeOp op, Node node, Collection<Node> exits, Collection<Invoke> invokes) {
+        int weight = 0;
+        for (Node usage : node.usages()) {
+            boolean escapes = op.escape(node, usage);
+            if (escapes) {
+                if (usage instanceof FrameState) {
+                    // nothing to do...
+                } else if (usage instanceof Invoke) {
+                    invokes.add((Invoke) usage);
+                } else {
+                    exits.add(usage);
+                    if (!GraalOptions.TraceEscapeAnalysis) {
+                        break;
+                    }
+                }
+            } else {
+                weight++;
+            }
+        }
+        return weight;
+    }
+
+    public static class EscapeField {
+
+        private String name;
+        private Object representation;
+        private CiKind kind;
+
+        public EscapeField(String name, Object representation, CiKind kind) {
+            this.name = name;
+            this.representation = representation;
+            this.kind = kind;
+        }
+
+        public String name() {
+            return name;
+        }
+
+        public Object representation() {
+            return representation;
+        }
+
+        public CiKind kind() {
+            return kind;
+        }
+
+        @Override
+        public String toString() {
+            return name();
+        }
+    }
+
+    public static interface EscapeOp extends Op {
+
+        boolean canAnalyze(Node node);
+
+        boolean escape(Node node, Node usage);
+
+        EscapeField[] fields(Node node);
+
+        void beforeUpdate(Node node, Node usage);
+
+        void updateState(Node node, Node current, Map<Object, EscapeField> fields, Map<EscapeField, Node> fieldState);
+
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/GraphBuilderPhase.java	Fri Jul 01 18:24:04 2011 +0200
@@ -201,7 +201,7 @@
         List<Loop> loops = LoopUtil.computeLoops(graph);
         NodeBitMap loopExits = graph.createNodeBitMap();
         for (Loop loop : loops) {
-            loopExits.markAll(loop.exist());
+            loopExits.setUnion(loop.exits());
         }
 
         // remove Placeholders
@@ -325,12 +325,12 @@
                     Merge merge = new Merge(graph);
                     assert p.predecessors().size() == 1 : "predecessors size: " + p.predecessors().size();
                     FixedNode next = p.next();
-                    p.setNext(null);
                     EndNode end = new EndNode(graph);
-                    p.replaceAndDelete(end);
+                    p.setNext(end);
                     merge.setNext(next);
                     merge.addEnd(end);
                     merge.setStateAfter(existingState);
+                    p.setStateAfter(existingState.duplicate(bci));
                     if (!(next instanceof LoopEnd)) {
                         target.firstInstruction = merge;
                     }
@@ -436,12 +436,17 @@
             p.setStateAfter(frameState.duplicateWithoutStack(bci));
 
             Value currentExceptionObject;
+            ExceptionObject newObj = null;
             if (exceptionObject == null) {
-                currentExceptionObject = new ExceptionObject(graph);
+                newObj = new ExceptionObject(graph);
+                currentExceptionObject = newObj;
             } else {
                 currentExceptionObject = exceptionObject;
             }
             FrameState stateWithException = frameState.duplicateWithException(bci, currentExceptionObject);
+            if (newObj != null) {
+                newObj.setStateAfter(stateWithException);
+            }
             FixedNode target = createTarget(dispatchBlock, stateWithException);
             if (exceptionObject == null) {
                 ExceptionObject eObj = (ExceptionObject) currentExceptionObject;
@@ -964,7 +969,7 @@
             append(deoptimize);
             frameState.pushReturn(resultType, Constant.defaultForKind(resultType, graph));
         } else {
-            Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), method.typeProfile(bci()), graph);
+            Invoke invoke = new Invoke(bci(), opcode, resultType.stackKind(), args, target, target.signature().returnType(method.holder()), graph);
             Value result = appendWithBCI(invoke);
             invoke.setExceptionEdge(handleException(null, bci()));
             frameState.pushReturn(resultType, result);
@@ -1201,6 +1206,7 @@
         if (block.firstInstruction == null) {
             if (block.isLoopHeader) {
                 LoopBegin loopBegin = new LoopBegin(graph);
+                loopBegin.addEnd(new EndNode(graph));
                 LoopEnd loopEnd = new LoopEnd(graph);
                 loopEnd.setLoopBegin(loopBegin);
                 Placeholder pBegin = new Placeholder(graph);
@@ -1231,7 +1237,14 @@
             } else {
                 EndNode end = new EndNode(graph);
                 ((Merge) result).addEnd(end);
-                result = end;
+                Placeholder p = new Placeholder(graph);
+                int bci = block.startBci;
+                if (block instanceof ExceptionBlock) {
+                    bci = ((ExceptionBlock) block).deoptBci;
+                }
+                p.setStateAfter(stateAfter.duplicate(bci));
+                p.setNext(end);
+                result = p;
             }
         }
         assert !(result instanceof LoopBegin || result instanceof Merge);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/InliningPhase.java	Fri Jul 01 18:24:04 2011 +0200
@@ -32,118 +32,84 @@
 import com.oracle.max.graal.compiler.ir.Deoptimize.DeoptAction;
 import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
+import com.sun.cri.bytecode.*;
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
 
 
 public class InliningPhase extends Phase {
 
+    public static final HashMap<RiMethod, Integer> methodCount = new HashMap<RiMethod, Integer>();
+
     private final GraalCompilation compilation;
     private final IR ir;
 
-    private final Queue<Invoke> invokes = new ArrayDeque<Invoke>();
-    private final Queue<RiMethod> methods = new ArrayDeque<RiMethod>();
+    private int inliningSize;
+    private final Collection<Invoke> hints;
 
-    private final Map<Invoke, RiMethod> parentMethod = new HashMap<Invoke, RiMethod>();
-    private int inliningSize;
-    private final boolean trace;
-
-    public InliningPhase(GraalCompilation compilation, IR ir, boolean trace) {
+    public InliningPhase(GraalCompilation compilation, IR ir, Collection<Invoke> hints) {
         this.compilation = compilation;
         this.ir = ir;
-        this.trace = trace;
+        this.hints = hints;
     }
 
-    private void addToQueue(Invoke invoke, RiMethod method) {
-        invokes.add(invoke);
-        methods.add(method);
-        inliningSize += method.codeSize();
-    }
+    private Queue<Invoke> newInvokes = new ArrayDeque<Invoke>();
+    private Graph graph;
 
-    public static HashMap<RiMethod, Integer> methodCount = new HashMap<RiMethod, Integer>();
     @Override
     protected void run(Graph graph) {
+        this.graph = graph;
+
         float ratio = GraalOptions.MaximumInlineRatio;
         inliningSize = compilation.method.codeSize();
+
+        if (hints != null) {
+            newInvokes.addAll(hints);
+        } else {
+            for (Invoke invoke : graph.getNodes(Invoke.class)) {
+                newInvokes.add(invoke);
+            }
+        }
+
         for (int iterations = 0; iterations < GraalOptions.MaximumInlineLevel; iterations++) {
-            for (Invoke invoke : graph.getNodes(Invoke.class)) {
-                RiMethod parent = parentMethod.get(invoke);
-                if (parent == null) {
-                    parent = compilation.method;
-                }
-                RiTypeProfile profile = parent.typeProfile(invoke.bci);
-                if (!checkInvokeConditions(invoke)) {
-                    continue;
-                }
-                if (invoke.target.canBeStaticallyBound()) {
-                    if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) {
-                        addToQueue(invoke, invoke.target);
-                    }
-                } else {
-                    RiMethod concrete = invoke.target.holder().uniqueConcreteMethod(invoke.target);
-                    if (concrete != null) {
-                        if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
-                            if (trace) {
-                                String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false);
-                                String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false);
-                                TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName);
-                            }
-                            compilation.assumptions.recordConcreteMethod(invoke.target, concrete);
-                            addToQueue(invoke, concrete);
+            Queue<Invoke> queue = newInvokes;
+            newInvokes = new ArrayDeque<Invoke>();
+            for (Invoke invoke : queue) {
+                if (!invoke.isDeleted()) {
+                    RiMethod code = inlineInvoke(invoke, iterations, ratio);
+                    if (code != null) {
+                        inliningSize += code.codeSize();
+                        if (inliningSize > GraalOptions.MaximumInstructionCount) {
+                            break;
                         }
-                    } else if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) {
-                        if (GraalOptions.InlineWithTypeCheck) {
-                            // type check and inlining...
-                            concrete = profile.types[0].resolveMethodImpl(invoke.target);
-                            if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
-                                IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph);
-                                FixedGuard guard = new FixedGuard(isType, graph);
-                                assert invoke.predecessors().size() == 1;
-                                invoke.predecessors().get(0).successors().replace(invoke, guard);
-                                guard.setNext(invoke);
 
-                                if (trace) {
-                                    TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]);
-                                }
-                                addToQueue(invoke, concrete);
+                        inlineMethod(invoke, code);
+                        if (GraalOptions.TraceInlining) {
+                            if (methodCount.get(code) == null) {
+                                methodCount.put(code, 1);
+                            } else {
+                                methodCount.put(code, methodCount.get(code) + 1);
                             }
                         }
                     }
                 }
-                if (inliningSize > GraalOptions.MaximumInstructionCount) {
-                    break;
-                }
             }
-
-            assert invokes.size() == methods.size();
-            if (invokes.isEmpty()) {
-                break;
-            }
-
-            Invoke invoke;
-            while ((invoke = invokes.poll()) != null) {
-                RiMethod method = methods.remove();
-                inlineMethod(invoke, method);
-
-                if (methodCount.get(method) == null) {
-                    methodCount.put(method, 1);
-                } else {
-                    methodCount.put(method, methodCount.get(method) + 1);
-                }
-            }
-            DeadCodeEliminationPhase dce = new DeadCodeEliminationPhase();
-            dce.apply(graph);
-
             if (inliningSize > GraalOptions.MaximumInstructionCount) {
-                if (trace) {
+                if (GraalOptions.TraceInlining) {
                     TTY.println("inlining stopped: MaximumInstructionCount reached");
                 }
                 break;
             }
+            if (newInvokes.isEmpty()) {
+                break;
+            }
+
+//            new DeadCodeEliminationPhase().apply(graph);
+
             ratio *= GraalOptions.MaximumInlineRatio;
         }
 
-        if (trace) {
+        if (GraalOptions.TraceInlining) {
             int inlined = 0;
             int duplicate = 0;
             for (Map.Entry<RiMethod, Integer> entry : methodCount.entrySet()) {
@@ -156,16 +122,90 @@
         }
     }
 
+    private RiMethod inlineInvoke(Invoke invoke, int iterations, float ratio) {
+        RiMethod parent = invoke.stateAfter().method();
+        RiTypeProfile profile = parent.typeProfile(invoke.bci);
+        if (!checkInvokeConditions(invoke)) {
+            return null;
+        }
+        if (invoke.opcode() == Bytecodes.INVOKESPECIAL || invoke.target.canBeStaticallyBound()) {
+            if (checkTargetConditions(invoke.target, iterations) && checkSizeConditions(invoke.target, invoke, profile, ratio)) {
+                return invoke.target;
+            }
+            return null;
+        }
+        if (invoke.receiver().exactType() != null) {
+            RiType exact = invoke.receiver().exactType();
+            assert exact.isSubtypeOf(invoke.target().holder()) : exact + " subtype of " + invoke.target().holder();
+            RiMethod resolved = exact.resolveMethodImpl(invoke.target());
+            if (checkTargetConditions(resolved, iterations) && checkSizeConditions(resolved, invoke, profile, ratio)) {
+                return resolved;
+            }
+            return null;
+        }
+        RiType holder = invoke.target().holder();
+
+        if (invoke.receiver().declaredType() != null) {
+            RiType declared = invoke.receiver().declaredType();
+            // the invoke target might be more specific than the holder (happens after inlining: locals lose their declared type...)
+            // TODO (ls) fix this
+            if (declared.isResolved() && declared.isSubtypeOf(invoke.target().holder())) {
+                holder = declared;
+            }
+        }
+
+        RiMethod concrete = holder.uniqueConcreteMethod(invoke.target);
+        if (concrete != null) {
+            if (checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
+                if (GraalOptions.TraceInlining) {
+                    String targetName = CiUtil.format("%H.%n(%p):%r", invoke.target, false);
+                    String concreteName = CiUtil.format("%H.%n(%p):%r", concrete, false);
+                    TTY.println("recording concrete method assumption: %s -> %s", targetName, concreteName);
+                }
+                compilation.assumptions.recordConcreteMethod(invoke.target, concrete);
+                return concrete;
+            }
+            return null;
+        }
+        if (profile != null && profile.probabilities != null && profile.probabilities.length > 0 && profile.morphism == 1) {
+            if (GraalOptions.InlineWithTypeCheck) {
+                // type check and inlining...
+                concrete = profile.types[0].resolveMethodImpl(invoke.target);
+                if (concrete != null && checkTargetConditions(concrete, iterations) && checkSizeConditions(concrete, invoke, profile, ratio)) {
+                    IsType isType = new IsType(invoke.receiver(), profile.types[0], compilation.graph);
+                    FixedGuard guard = new FixedGuard(graph);
+                    guard.setNode(isType);
+                    assert invoke.predecessors().size() == 1;
+                    invoke.predecessors().get(0).successors().replace(invoke, guard);
+                    guard.setNext(invoke);
+
+                    if (GraalOptions.TraceInlining) {
+                        TTY.println("inlining with type check, type probability: %5.3f", profile.probabilities[0]);
+                    }
+                    return concrete;
+                }
+                return null;
+            } else {
+                if (GraalOptions.TraceInlining) {
+                    TTY.println("not inlining %s because GraalOptions.InlineWithTypeCheck == false", methodName(invoke.target, invoke));
+                }
+                return null;
+            }
+        } else {
+            if (GraalOptions.TraceInlining) {
+                TTY.println("not inlining %s because no monomorphic receiver could be found", methodName(invoke.target, invoke));
+            }
+            return null;
+        }
+    }
+
     private String methodName(RiMethod method) {
         return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
     }
 
     private String methodName(RiMethod method, Invoke invoke) {
         if (invoke != null) {
-            RiMethod parent = parentMethod.get(invoke);
-            if (parent == null) {
-                parent = compilation.method;
-            }
+            RiMethod parent = invoke.stateAfter().method();
             return parent.name() + "@" + invoke.bci + ": " + CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
         } else {
             return CiUtil.format("%H.%n(%p):%r", method, false) + " (" + method.codeSize() + " bytes)";
@@ -174,31 +214,31 @@
 
     private boolean checkInvokeConditions(Invoke invoke) {
         if (invoke.stateAfter() == null) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because the invoke has no after state", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (invoke.stateAfter().locksSize() > 0) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because of locks", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (!invoke.target.isResolved()) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because the invoke target is unresolved", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (invoke.predecessors().size() == 0) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because the invoke is dead code", methodName(invoke.target, invoke));
             }
             return false;
         }
         if (invoke.stateAfter() == null) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because of missing frame state", methodName(invoke.target, invoke));
             }
         }
@@ -207,31 +247,31 @@
 
     private boolean checkTargetConditions(RiMethod method, int iterations) {
         if (!method.isResolved()) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because it is unresolved", methodName(method));
             }
             return false;
         }
         if (Modifier.isNative(method.accessFlags())) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because it is a native method", methodName(method));
             }
             return false;
         }
         if (Modifier.isAbstract(method.accessFlags())) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because it is an abstract method", methodName(method));
             }
             return false;
         }
         if (!method.holder().isInitialized()) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because of non-initialized class", methodName(method));
             }
             return false;
         }
         if (method == compilation.method && iterations > GraalOptions.MaximumRecursiveInlineLevel) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because of recursive inlining limit", methodName(method));
             }
             return false;
@@ -240,8 +280,12 @@
     }
 
     private boolean checkStaticSizeConditions(RiMethod method, Invoke invoke) {
-        if (method.codeSize() > GraalOptions.MaximumInlineSize) {
-            if (trace) {
+        int maximumSize = GraalOptions.MaximumInlineSize;
+        if (hints != null && hints.contains(invoke)) {
+            maximumSize = GraalOptions.MaximumFreqInlineSize;
+        }
+        if (method.codeSize() > maximumSize) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because of code size (size: %d, max size: %d)", methodName(method, invoke), method.codeSize(), GraalOptions.MaximumInlineSize);
             }
             return false;
@@ -253,10 +297,7 @@
         int maximumSize = GraalOptions.MaximumTrivialSize;
         float ratio = 0;
         if (profile != null && profile.count > 0) {
-            RiMethod parent = parentMethod.get(invoke);
-            if (parent == null) {
-                parent = compilation.method;
-            }
+            RiMethod parent = invoke.stateAfter().method();
             ratio = profile.count / (float) parent.invocationCount();
             if (ratio >= GraalOptions.FreqInlineRatio) {
                 maximumSize = GraalOptions.MaximumFreqInlineSize;
@@ -264,13 +305,16 @@
                 maximumSize = GraalOptions.MaximumInlineSize;
             }
         }
+        if (hints != null && hints.contains(invoke)) {
+            maximumSize = GraalOptions.MaximumFreqInlineSize;
+        }
         if (method.codeSize() > maximumSize) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("not inlining %s because of code size (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile);
             }
             return false;
         }
-        if (trace) {
+        if (GraalOptions.TraceInlining) {
             TTY.println("inlining %s (size: %d, max size: %d, ratio %5.3f, %s)", methodName(method, invoke), method.codeSize(), maximumSize, ratio, profile);
         }
         return true;
@@ -286,12 +330,12 @@
         CompilerGraph graph;
         Object stored = GraphBuilderPhase.cachedGraphs.get(method);
         if (stored != null) {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("Reusing graph for %s, locals: %d, stack: %d", methodName(method, invoke), method.maxLocals(), method.maxStackSize());
             }
             graph = (CompilerGraph) stored;
         } else {
-            if (trace) {
+            if (GraalOptions.TraceInlining) {
                 TTY.println("Building graph for %s, locals: %d, stack: %d", methodName(method, invoke), method.maxLocals(), method.maxStackSize());
             }
             graph = new CompilerGraph(null);
@@ -337,7 +381,7 @@
             }
         }
 
-        if (trace) {
+        if (GraalOptions.TraceInlining) {
             TTY.println("inlining %s: %d frame states, %d nodes", methodName(method), frameStates.size(), nodes.size());
         }
 
@@ -345,7 +389,8 @@
         assert invoke.predecessors().size() == 1 : "size: " + invoke.predecessors().size();
         FixedNodeWithNext pred;
         if (withReceiver) {
-            FixedGuard clipNode = new FixedGuard(new IsNonNull(parameters[0], compilation.graph), compilation.graph);
+            FixedGuard clipNode = new FixedGuard(compilation.graph);
+            clipNode.setNode(new IsNonNull(parameters[0], compilation.graph));
             pred = clipNode;
         } else {
             pred = new Placeholder(compilation.graph);
@@ -357,7 +402,7 @@
 
         for (Node node : duplicates.values()) {
             if (node instanceof Invoke) {
-                parentMethod.put((Invoke) node, method);
+                newInvokes.add((Invoke) node);
             }
         }
 
@@ -425,7 +470,7 @@
             }
         }
 
-        if (trace) {
+        if (GraalOptions.TraceInlining) {
             ir.printGraph("After inlining " + CiUtil.format("%H.%n(%p):%r", method, false), compilation.graph);
         }
     }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/LoopPhase.java	Fri Jul 01 18:24:04 2011 +0200
@@ -26,6 +26,7 @@
 
 import com.oracle.max.graal.compiler.ir.*;
 import com.oracle.max.graal.compiler.util.*;
+import com.oracle.max.graal.compiler.util.LoopUtil.Loop;
 import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
 import com.sun.cri.ci.*;
@@ -35,14 +36,22 @@
 
     @Override
     protected void run(Graph graph) {
-        for (LoopBegin n : graph.getNodes(LoopBegin.class)) {
-            doLoop(n);
+        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);
         }
     }
 
-    private void doLoop(LoopBegin loopBegin) {
-        NodeBitMap loopNodes = LoopUtil.computeLoopNodes(loopBegin);
-        List<LoopCounter> counters = findLoopCounters(loopBegin, loopNodes);
+    private void doLoopCounters(Loop loop) {
+        LoopBegin loopBegin = loop.loopBegin();
+        List<LoopCounter> counters = findLoopCounters(loopBegin, loop.nodes());
         mergeLoopCounters(counters, loopBegin);
     }
 
@@ -102,6 +111,9 @@
                 if (phi.valueCount() == 2) {
                     Value backEdge = phi.valueAt(1);
                     Value init = phi.valueAt(0);
+                    if (loopNodes.isNew(init) || loopNodes.isNew(backEdge)) {
+                        continue;
+                    }
                     if (loopNodes.isMarked(init)) {
                         // try to reverse init/backEdge order
                         Value tmp = backEdge;
@@ -127,7 +139,7 @@
                             useCounterAfterAdd = true;
                         }
                     }
-                    if (stride != null && !loopNodes.isMarked(stride)) {
+                    if (stride != null && !loopNodes.isNew(stride) &&  !loopNodes.isMarked(stride)) {
                         Graph graph = loopBegin.graph();
                         LoopCounter counter = new LoopCounter(init.kind, init, stride, loopBegin, graph);
                         counters.add(counter);
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/phases/Phase.java	Fri Jul 01 18:24:04 2011 +0200
@@ -48,6 +48,10 @@
     }
 
     public final void apply(Graph graph) {
+        apply(graph, true);
+    }
+
+    public final void apply(Graph graph, boolean plotOnError) {
         assert graph != null && (!shouldVerify || graph.verify());
 
         int startDeletedNodeCount = graph.getDeletedNodeCount();
@@ -62,7 +66,21 @@
             GraalTimers.get(getName()).start();
         }
         //System.out.println("Starting Phase " + getName());
-        run(graph);
+        try {
+            run(graph);
+        } catch (AssertionError t) {
+            GraalCompilation compilation = GraalCompilation.compilation();
+            if (compilation.compiler.isObserved() && plotOnError) {
+                compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "AssertionError in " + getName(), graph, true, false, true));
+            }
+            throw t;
+        } catch (RuntimeException t) {
+            GraalCompilation compilation = GraalCompilation.compilation();
+            if (compilation.compiler.isObserved() && plotOnError) {
+                compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "RuntimeException in " + getName(), graph, true, false, true));
+            }
+            throw t;
+        }
         //System.out.println("Finished Phase " + getName());
         if (GraalOptions.Time) {
             GraalTimers.get(getName()).stop();
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/Block.java	Fri Jul 01 18:24:04 2011 +0200
@@ -182,4 +182,46 @@
     public void setInstructions(List<Node> instructions) {
         this.instructions = instructions;
     }
+
+    public static void iteratePostOrder(List<Block> blocks, BlockClosure closure) {
+        ArrayList<Block> startBlocks = new ArrayList<Block>();
+        for (Block block : blocks) {
+            if (block.getPredecessors().size() == 0) {
+                startBlocks.add(block);
+            }
+        }
+        iteratePostOrder(blocks, closure, startBlocks.toArray(new Block[startBlocks.size()]));
+    }
+
+    public static void iteratePostOrder(List<Block> blocks, BlockClosure closure, Block... startBlocks) {
+        BitMap visited = new BitMap(blocks.size());
+        LinkedList<Block> workList = new LinkedList<Block>();
+        for (Block block : startBlocks) {
+            workList.add(block);
+            visited.set(block.blockID());
+        }
+
+        while (!workList.isEmpty()) {
+            Block b = workList.remove();
+
+            closure.apply(b);
+
+            for (Block succ : b.getSuccessors()) {
+                if (!visited.get(succ.blockID())) {
+                    boolean delay = false;
+                    for (Block pred : succ.getPredecessors()) {
+                        if (!visited.get(pred.blockID()) && !(pred.lastNode instanceof LoopEnd)) {
+                            delay = true;
+                            break;
+                        }
+                    }
+
+                    if (!delay) {
+                        visited.set(succ.blockID());
+                        workList.add(succ);
+                    }
+                }
+            }
+        }
+    }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/schedule/IdentifyBlocksPhase.java	Fri Jul 01 18:24:04 2011 +0200
@@ -125,6 +125,7 @@
                         break;
                     }
                     currentNode = currentNode.singlePredecessor();
+                    assert !currentNode.isDeleted();
                 }
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/GraphUtil.java	Fri Jul 01 18:24:04 2011 +0200
@@ -0,0 +1,333 @@
+/*
+ * 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.max.graal.compiler.util;
+
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.ir.*;
+import com.oracle.max.graal.compiler.observer.*;
+import com.oracle.max.graal.compiler.value.*;
+import com.oracle.max.graal.graph.*;
+import com.oracle.max.graal.graph.NodeWorkList.*;
+
+public class GraphUtil {
+
+    public static interface ColoringLambda<T> {
+        T color(Iterable<T> incomming, Merge merge);
+        T danglingColor(Iterable<T> incomming, Merge merge);
+    }
+
+    /**
+     * colors down, applying the lambda at merge points, starting at the pre-colored points.
+     */
+    public static <T> void colorCFGDown(NodeMap<T> colors, ColoringLambda<T> lambda) {
+        Set<Merge> delayed = new HashSet<Merge>();
+        Set<Node> currentPoints = new HashSet<Node>();
+        Set<Node> otherPoints = new HashSet<Node>();
+        Set<Merge> otherMerges = new HashSet<Merge>();
+        for (Entry<Node, T> entry : colors.entries()) {
+            currentPoints.add(entry.getKey());
+        }
+        ArrayList<T> incomming = new ArrayList<T>(2);
+        while (!currentPoints.isEmpty()) {
+            for (Node node : currentPoints) {
+                otherMerges.addAll(colorCFGDownToMerge(node, colors.get(node), colors));
+            }
+            for (Merge merge : otherMerges) {
+                incomming.clear();
+                for (EndNode end : merge.cfgPredecessors()) {
+                    incomming.add(colors.get(end));
+                }
+                T color = lambda.color(incomming, merge);
+                if (color != null) {
+                    colors.set(merge, color);
+                    colors.set(merge.next(), color);
+                    otherPoints.add(merge.next());
+                    delayed.remove(merge);
+                } else {
+                    delayed.add(merge);
+                }
+            }
+            Set<Node> tmp = currentPoints;
+            currentPoints = otherPoints;
+            otherPoints = tmp;
+            otherPoints.clear();
+            otherMerges.clear();
+        }
+        for (Merge merge : delayed) {
+            T color = lambda.danglingColor(incomming, merge);
+            if (color != null) {
+                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) {
+        //System.out.println("colorCFGDownToMerge(" + from + ", " + color + ", colors)");
+        NodeFlood work = from.graph().createNodeFlood();
+        Collection<Merge> merges = new LinkedList<Merge>();
+        work.add(from);
+        for (Node node : work) {
+            //System.out.println("colorToMerge : work on " + node);
+            Node current = node;
+            while (current != null) {
+                //System.out.println("colorToMerge : current " + current);
+                if (current instanceof Merge) {
+                    merges.add((Merge) current);
+                    break;
+                }
+                colors.set(current, color);
+                if (current instanceof FixedNodeWithNext) {
+                    current = ((FixedNodeWithNext) current).next();
+                } else if (current instanceof EndNode) {
+                    current = ((EndNode) current).merge();
+                } else {
+                    if (current instanceof ControlSplit) {
+                        for (Node sux : current.cfgSuccessors()) {
+                            work.add(sux);
+                        }
+                    }
+                    current = null;
+                }
+            }
+        }
+        //System.out.println("return " + merges);
+        return merges;
+    }
+
+    public static interface ColorSplitingLambda<T> {
+        void fixSplit(Node oldNode, Node newNode, T color);
+        void fixNode(Node node, T color);
+        Value fixPhiInput(Value input, T color);
+        boolean explore(Node n);
+    }
+
+    // TODO (gd) rework that code around Phi handling : too complicated
+    public static <T> void splitFromColoring(NodeMap<T> coloring, ColorSplitingLambda<T> lambda) {
+        Map<Node, T> internalColoring = new HashMap<Node, T>();
+        NodeWorkList work = coloring.graph().createNodeWorkList();
+        for (Entry<Node, T> entry : coloring.entries()) {
+            T color = entry.getValue();
+            Node node = entry.getKey();
+            work.add(node);
+            internalColoring.put(node, color);
+        }
+        Set<T> colors = new HashSet<T>();
+        try {
+            for (Node node : work) {
+                //System.out.println("Split : work on " + node);
+                if (node instanceof Phi) {
+                    Phi phi = (Phi) node;
+                    Merge merge = phi.merge();
+                    for (int i = 0; i < phi.valueCount(); i++) {
+                        Value v = phi.valueAt(i);
+                        if (v != null) {
+                            T color = internalColoring.get(merge.phiPredecessorAt(i));
+                            if (color != null) {
+                                Value replace = lambda.fixPhiInput(v, color);
+                                if (replace != v) {
+                                    phi.setValueAt(i, replace);
+                                } else {
+                                    if (lambda.explore(v) && coloring.get(v) == null && !work.isNew(v)) {
+                                        //System.out.println("Split : Add input " + input + " to work from " + node);
+                                        work.add(v);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } else {
+                    boolean delay = false;
+                    colors.clear();
+                    T originalColoringColor = coloring.get(node);
+                    if (originalColoringColor == null && internalColoring.get(node) != null) {
+                        //System.out.println("Split : ori == null && intern != null -> continue");
+                        continue;
+                    }
+                    if (originalColoringColor == null) {
+                        for (Node usage : node.dataUsages()) {
+                            if (usage instanceof Phi) {
+                                Phi phi = (Phi) usage;
+                                Merge merge = phi.merge();
+                                //System.out.println("Split merge : " + merge + ".endCount = " + merge.endCount() + " phi " + phi + ".valueCount : " + phi.valueCount());
+                                for (int i = 0; i < phi.valueCount(); i++) {
+                                    Value v = phi.valueAt(i);
+                                    if (v == node) {
+                                        T color = internalColoring.get(merge.phiPredecessorAt(i));
+                                        if (color != null) {
+                                            colors.add(color);
+                                        }
+                                    }
+                                }
+                            } else {
+                                T color = internalColoring.get(usage);
+                                if (color == null) {
+                                    //System.out.println("Split : color from " + usage + " is null");
+                                    delay = true;
+                                    break;
+                                }
+                                colors.add(color);
+                            }
+                        }
+                        if (delay) {
+                            //System.out.println("Split : delay");
+                            work.addAgain(node);
+                            continue;
+                        }
+                    } else {
+                        colors.add(originalColoringColor);
+                    }
+                    if (colors.size() == 1) {
+                        //System.out.println("Split : 1 color, coloring, fixing");
+                        T color = colors.iterator().next();
+                        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);
+                            }
+                            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);
+                            LinkedList<Node> dataUsages = new LinkedList<Node>();
+                            for (Node usage : node.dataUsages()) {
+                                dataUsages.add(usage);
+                            }
+                            for (Node usage : dataUsages) {
+                                if (usage instanceof Phi) {
+                                    Phi phi = (Phi) usage;
+                                    Merge merge = phi.merge();
+                                    for (int i = 0; i < phi.valueCount(); i++) {
+                                        Value v = phi.valueAt(i);
+                                        if (v == node) {
+                                            T uColor = internalColoring.get(merge.endAt(i));
+                                            if (uColor == color) {
+                                                phi.setValueAt(i, (Value) newNode);
+                                            }
+                                        }
+                                    }
+                                } else {
+                                    T uColor = internalColoring.get(usage);
+                                    if (uColor == color) {
+                                        usage.inputs().replace(node, newNode);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    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) {
+                        for (Node usage : node.usages()) {
+                            if (!work.isNew(usage)) {
+                                work.add(usage);
+                            }
+                        }
+                    }
+
+                    if (node instanceof LoopEnd) {
+                        work.add(((LoopEnd) node).loopBegin());
+                    }
+
+                    for (Node input : node.dataInputs()) {
+                        if (lambda.explore(input) && coloring.get(input) == null && !work.isNew(input)) {
+                            //System.out.println("Split : Add input " + input + " to work from " + node);
+                            work.add(input);
+                        }
+                    }
+                }
+            }
+        } catch (InfiniteWorkException re) {
+            System.out.println("Infinite work, current queue :");
+            for (Node n : work) {
+                System.out.println(" - " + n);
+            }
+            GraalCompilation compilation = GraalCompilation.compilation();
+            if (compilation.compiler.isObserved()) {
+                NodeMap<T> debugColoring = coloring.graph().createNodeMap();
+                for (Entry<Node, T> entry : internalColoring.entrySet()) {
+                    debugColoring.set(entry.getKey(), entry.getValue());
+                }
+                Map<String, Object> debug = new HashMap<String, Object>();
+                debug.put("split", debugColoring);
+                compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "RuntimeException in split", coloring.graph(), true, false, true, debug));
+            }
+            throw re;
+        }
+        GraalCompilation compilation = GraalCompilation.compilation();
+        if (compilation.compiler.isObserved()) {
+            NodeMap<T> debugColoring = coloring.graph().createNodeMap();
+            for (Entry<Node, T> entry : internalColoring.entrySet()) {
+                debugColoring.set(entry.getKey(), entry.getValue());
+            }
+            Map<String, Object> debug = new HashMap<String, Object>();
+            debug.put("split", debugColoring);
+            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Split end!!", coloring.graph(), true, false, debug));
+        }
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/util/LoopUtil.java	Fri Jul 01 18:24:04 2011 +0200
@@ -23,22 +23,29 @@
 package com.oracle.max.graal.compiler.util;
 
 import java.util.*;
+import java.util.Map.Entry;
 
+import com.oracle.max.graal.compiler.*;
 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.util.GraphUtil.ColorSplitingLambda;
+import com.oracle.max.graal.compiler.util.GraphUtil.ColoringLambda;
+import com.oracle.max.graal.compiler.value.*;
 import com.oracle.max.graal.graph.*;
+import com.sun.cri.ci.*;
 
 public class LoopUtil {
 
     public static class Loop {
         private final LoopBegin loopBegin;
-        private final NodeBitMap nodes;
+        private NodeBitMap nodes;
         private Loop parent;
-        private final List<FixedNode> exits;
-        public Loop(LoopBegin loopBegin, NodeBitMap nodes) {
+        private NodeBitMap exits;
+        public Loop(LoopBegin loopBegin, NodeBitMap nodes, NodeBitMap exits) {
             this.loopBegin = loopBegin;
             this.nodes = nodes;
-            this.exits = new LinkedList<FixedNode>();
+            this.exits = exits;
         }
 
         public LoopBegin loopBegin() {
@@ -53,38 +60,42 @@
             return parent;
         }
 
-        public List<FixedNode> exist() {
+        public NodeBitMap exits() {
             return exits;
         }
 
         public void setParent(Loop parent) {
             this.parent = parent;
         }
+
+        public boolean isChild(Loop loop) {
+            return loop.parent != null && (loop.parent == this || loop.parent.isChild(this));
+        }
+    }
+
+    private static class PeelingResult {
+        public final FixedNode begin;
+        public final FixedNode end;
+        public final NodeMap<Placeholder> exits;
+        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) {
+            this.begin = begin;
+            this.end = end;
+            this.exits = exits;
+            this.phis = phis;
+            this.phiInits = phiInits;
+            this.dataOut = dataOut;
+        }
     }
 
     public static List<Loop> computeLoops(Graph graph) {
         List<Loop> loops = new LinkedList<LoopUtil.Loop>();
         for (LoopBegin loopBegin : graph.getNodes(LoopBegin.class)) {
             NodeBitMap nodes = computeLoopNodes(loopBegin);
-            Loop loop = new Loop(loopBegin, nodes);
-            NodeFlood workCFG = graph.createNodeFlood();
-            workCFG.add(loopBegin.loopEnd());
-            for (Node n : workCFG) {
-                if (n == loopBegin) {
-                    continue;
-                }
-                if (IdentifyBlocksPhase.trueSuccessorCount(n) > 1) {
-                    for (Node sux : n.cfgSuccessors()) {
-                        if (!nodes.isMarked(sux) && sux instanceof FixedNode) {
-                            loop.exits.add((FixedNode) sux);
-                        }
-                    }
-                }
-                for (Node pred : n.cfgPredecessors()) {
-                    workCFG.add(pred);
-                }
-            }
-            loops.add(loop);
+            NodeBitMap exits = computeLoopExits(loopBegin, nodes);
+            loops.add(new Loop(loopBegin, nodes, exits));
         }
         for (Loop loop : loops) {
             for (Loop other : loops) {
@@ -98,20 +109,117 @@
         return loops;
     }
 
-    public static NodeBitMap computeLoopNodes(LoopBegin loopBegin) {
-        LoopEnd loopEnd = loopBegin.loopEnd();
-        NodeBitMap loopNodes = loopBegin.graph().createNodeBitMap();
-        NodeFlood workCFG = loopBegin.graph().createNodeFlood();
-        NodeFlood workData1 = loopBegin.graph().createNodeFlood();
-        NodeFlood workData2 = loopBegin.graph().createNodeFlood();
-        workCFG.add(loopEnd);
+    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) {
-            workData1.add(n);
-            workData2.add(n);
-            loopNodes.mark(n);
             if (n == loopBegin) {
                 continue;
             }
+            if (IdentifyBlocksPhase.trueSuccessorCount(n) > 1) {
+                for (Node sux : n.cfgSuccessors()) {
+                    if (!nodes.isMarked(sux) && sux instanceof FixedNode) {
+                        exits.mark(sux);
+                    }
+                }
+            }
+            for (Node pred : n.cfgPredecessors()) {
+                workCFG.add(pred);
+            }
+        }
+        return exits;
+    }
+
+    public static NodeBitMap computeLoopNodes(LoopBegin loopBegin) {
+        return computeLoopNodesFrom(loopBegin, loopBegin.loopEnd());
+    }
+    private static boolean recurse = false;
+    public static NodeBitMap computeLoopNodesFrom(LoopBegin loopBegin, FixedNode from) {
+        NodeFlood workData1 = loopBegin.graph().createNodeFlood();
+        NodeFlood workData2 = loopBegin.graph().createNodeFlood();
+        NodeBitMap loopNodes = markUpCFG(loopBegin, from);
+        loopNodes.mark(loopBegin);
+        for (Node n : loopNodes) {
+            workData1.add(n);
+            workData2.add(n);
+        }
+        NodeBitMap inOrAfter = loopBegin.graph().createNodeBitMap();
+        for (Node n : workData1) {
+            markWithState(n, inOrAfter);
+            for (Node usage : n.dataUsages()) {
+                if (usage instanceof Phi) { // filter out data graph cycles
+                    Phi phi = (Phi) usage;
+                    if (!phi.isDead()) {
+                        Merge merge = phi.merge();
+                        if (merge instanceof LoopBegin) {
+                            LoopBegin phiLoop = (LoopBegin) merge;
+                            int backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd());
+                            if (phi.valueAt(backIndex) == n) {
+                                continue;
+                            }
+                        }
+                    }
+                }
+                workData1.add(usage);
+            }
+        }
+        NodeBitMap inOrBefore = loopBegin.graph().createNodeBitMap();
+        for (Node n : workData2) {
+            markWithState(n, inOrBefore);
+            if (n instanceof Phi) { // filter out data graph cycles
+                Phi phi = (Phi) n;
+                if (!phi.isDead()) {
+                    int backIndex = -1;
+                    Merge merge = phi.merge();
+                    if (!loopNodes.isMarked(merge) && merge instanceof LoopBegin) {
+                        LoopBegin phiLoop = (LoopBegin) merge;
+                        backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd());
+                    }
+                    for (int i = 0; i < phi.valueCount(); i++) {
+                        if (i != backIndex) {
+                            workData2.add(phi.valueAt(i));
+                        }
+                    }
+                }
+            } else {
+                for (Node input : n.dataInputs()) {
+                    workData2.add(input);
+                }
+            }
+            if (n instanceof Merge) { //add phis & counters
+                for (Node usage : n.dataUsages()) {
+                    workData2.add(usage);
+                }
+            }
+        }
+        if (!recurse) {
+            recurse = true;
+            GraalCompilation compilation = GraalCompilation.compilation();
+            if (compilation.compiler.isObserved()) {
+                Map<String, Object> debug = new HashMap<String, Object>();
+                debug.put("loopNodes", loopNodes);
+                debug.put("inOrAfter", inOrAfter);
+                debug.put("inOrBefore", inOrBefore);
+                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;
+    }
+
+    private static NodeBitMap markUpCFG(LoopBegin loopBegin, FixedNode from) {
+        NodeFlood workCFG = loopBegin.graph().createNodeFlood();
+        workCFG.add(from);
+        NodeBitMap loopNodes = loopBegin.graph().createNodeBitMap();
+        for (Node n : workCFG) {
+            if (n == loopBegin) {
+                continue;
+            }
+            loopNodes.mark(n);
             if (n instanceof LoopBegin) {
                 workCFG.add(((LoopBegin) n).loopEnd());
             }
@@ -119,27 +227,478 @@
                 workCFG.add(pred);
             }
         }
-        NodeBitMap inOrAfter = loopBegin.graph().createNodeBitMap();
-        for (Node n : workData1) {
-            inOrAfter.mark(n);
-            for (Node usage : n.dataUsages()) {
-                workData1.add(usage);
+        return loopNodes;
+    }
+
+    public static void ifDoWhileTransform(Loop loop, If split) {
+        assert loop.nodes().isMarked(split);
+        FixedNode noExit = split.trueSuccessor();
+        FixedNode exit = split.falseSuccessor();
+        if (loop.nodes().isMarked(exit) && !loop.nodes().isMarked(noExit)) {
+            FixedNode tmp = noExit;
+            noExit = exit;
+            exit = tmp;
+        }
+        assert !loop.nodes().isMarked(exit);
+        assert loop.nodes().isMarked(noExit);
+
+        PeelingResult peeling = preparePeeling(loop, split);
+        rewirePeeling(peeling, loop, split);
+        // TODO (gd) move peeled part to the end, rewire dataOut
+    }
+
+    public static void peelLoop(Loop loop) {
+        LoopEnd loopEnd = loop.loopBegin().loopEnd();
+        PeelingResult peeling = preparePeeling(loop, loopEnd);
+        GraalCompilation compilation = GraalCompilation.compilation();
+        if (compilation.compiler.isObserved()) {
+            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "After peeling preparation", loopEnd.graph(), true, false));
+        }
+        /*System.out.println("Peeling : ");
+        System.out.println(" begin = " + peeling.begin);
+        System.out.println(" end = " + peeling.end);
+        System.out.println(" Phis :");
+        for (Entry<Node, Placeholder> entry : peeling.phis.entries()) {
+            System.out.println("  - " + entry.getKey() + " -> " + entry.getValue());
+        }
+        System.out.println(" Exits :");
+        for (Entry<Node, Placeholder> entry : peeling.exits.entries()) {
+            System.out.println("  - " + entry.getKey() + " -> " + entry.getValue());
+        }
+        System.out.println(" PhiInits :");
+        for (Entry<Node, Node> entry : peeling.phiInits.entries()) {
+            System.out.println("  - " + entry.getKey() + " -> " + entry.getValue());
+        }
+        System.out.println(" DataOut :");
+        for (Entry<Node, Node> entry : peeling.dataOut.entries()) {
+            System.out.println("  - " + entry.getKey() + " -> " + entry.getValue());
+        }*/
+        rewirePeeling(peeling, loop, loopEnd);
+        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) {
+            parent.nodes = computeLoopNodes(loop.loopBegin);
+            parent.exits = computeLoopExits(parent.loopBegin, parent.nodes);
+            parent = parent.parent;
+        }
+    }
+
+    private static void rewirePeeling(PeelingResult peeling, Loop loop, FixedNode from) {
+        LoopBegin loopBegin = loop.loopBegin();
+        Graph graph = loopBegin.graph();
+        Node loopPred = loopBegin.singlePredecessor();
+        loopPred.successors().replace(loopBegin.forwardEdge(), peeling.begin);
+        NodeBitMap loopNodes = loop.nodes();
+        Node originalLast = from;
+        if (originalLast == loopBegin.loopEnd()) {
+            originalLast = loopBegin.loopEnd().singlePredecessor();
+        }
+        int size = originalLast.successors().size();
+        boolean found = false;
+        for (int i = 0; i < size; i++) {
+            Node sux = originalLast.successors().get(i);
+            if (sux == null) {
+                continue;
+            }
+            if (loopNodes.isMarked(sux)) {
+                assert !found;
+                peeling.end.successors().set(i, loopBegin.forwardEdge());
+                found = true;
             }
         }
-        NodeBitMap inOrBefore = loopBegin.graph().createNodeBitMap();
-        for (Node n : workData2) {
-            inOrBefore.mark(n);
-            for (Node input : n.dataInputs()) {
-                workData2.add(input);
+        assert found;
+        int phiInitIndex = loopBegin.phiPredecessorIndex(loopBegin.forwardEdge());
+        for (Entry<Node, Placeholder> entry : peeling.phis.entries()) {
+            Phi phi = (Phi) entry.getKey();
+            Placeholder p = entry.getValue();
+            p.replaceAndDelete(phi.valueAt(phiInitIndex));
+        }
+        for (Entry<Node, Node> entry : peeling.phiInits.entries()) {
+            Phi phi = (Phi) entry.getKey();
+            Node newInit = entry.getValue();
+            phi.setValueAt(phiInitIndex, (Value) newInit);
+        }
+
+        if (from == loopBegin.loopEnd()) {
+            for (LoopCounter counter : loopBegin.counters()) {
+                counter.setInit(new IntegerAdd(counter.kind, counter.init(), counter.stride(), graph));
             }
-            if (n instanceof Merge) { //add phis & counters
-                for (Node usage : n.dataUsages()) {
-                    workData2.add(usage);
+        }
+        NodeMap<NodeMap<Value>> newExitValues = graph.createNodeMap();
+        List<Node> exitPoints = new LinkedList<Node>();
+        for (Node exit : loop.exits()) {
+            exitPoints.add(exit);
+        }
+        for (Entry<Node, Placeholder> entry : peeling.exits.entries()) {
+            Placeholder original = (Placeholder) entry.getKey();
+            Placeholder newExit = entry.getValue();
+            FixedNode next = original.next();
+            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);
+            original.setNext(oEnd);
+            newExit.setStateAfter(null);
+            newExit.replaceAndDelete(nEnd);
+
+            exitPoints.add(nEnd);
+        }
+
+        for (Entry<Node, Placeholder> entry : peeling.exits.entries()) {
+            Placeholder original = (Placeholder) 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);
+
+                    phiMap = newExitValues.get(newValue);
+                    if (phiMap == null) {
+                        phiMap = graph.createNodeMap();
+                        newExitValues.set(newValue, phiMap);
+                    }
+                    phiMap.set(original, (Value) originalValue);
+                    phiMap.set(nEnd, (Value) newValue);
+                }
+            }
+            /*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);
+                }
+            }*/
+        }
+        for (Entry<Node, NodeMap<Value>> entry : newExitValues.entries()) {
+            Value original = (Value) entry.getKey();
+            NodeMap<Value> pointToValue = entry.getValue();
+            for (Node exit : exitPoints) {
+                Node valueAtExit = pointToValue.get(exit);
+                if (valueAtExit == null) {
+                    pointToValue.set(exit, original);
                 }
             }
         }
-        inOrBefore.setIntersect(inOrAfter);
-        loopNodes.setUnion(inOrBefore);
-        return loopNodes;
+
+        replaceValuesAtLoopExits(newExitValues, loop, exitPoints);
+    }
+
+    private static void replaceValuesAtLoopExits(final NodeMap<NodeMap<Value>> newExitValues, Loop loop, List<Node> exitPoints) {
+        Graph graph = loop.loopBegin().graph();
+        final NodeMap<Node> colors = graph.createNodeMap();
+
+        // prepare inital colors
+        for (Node exitPoint : exitPoints) {
+            colors.set(exitPoint, exitPoint);
+        }
+
+        /*System.out.println("newExitValues");
+        for (Entry<Node, NodeMap<Value>> entry : newExitValues.entries()) {
+            System.out.println(" - " + entry.getKey() + " :");
+            for (Entry<Node, Value> entry2 : entry.getValue().entries()) {
+                System.out.println("    + " + entry2.getKey() + " -> " + entry2.getValue());
+            }
+        }*/
+
+        // color
+        GraphUtil.colorCFGDown(colors, new ColoringLambda<Node>() {
+            @Override
+            public Node color(Iterable<Node> incomming, Merge merge) {
+                Node color = null;
+                for (Node c : incomming) {
+                    if (c == null) {
+                        return null;
+                    }
+                    if (color == null) {
+                        color = c;
+                    } else if (color != c) {
+                        return merge;
+                    }
+                }
+                return color;
+            }
+            @Override
+            public Node danglingColor(Iterable<Node> incomming, Merge merge) {
+                Node color = null;
+                for (Node c : incomming) {
+                    if (color == null) {
+                        color = c;
+                    } else if (color != c) {
+                        return merge;
+                    }
+                }
+                assert color != null;
+                return color;
+            }
+        });
+
+        final NodeBitMap inOrBefore = inOrBefore(loop);
+
+        GraalCompilation compilation = GraalCompilation.compilation();
+        if (compilation.compiler.isObserved()) {
+            Map<String, Object> debug = new HashMap<String, Object>();
+            debug.put("loopExits", colors);
+            debug.put("inOrBefore", inOrBefore);
+            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) {
+                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);
+                    return value;
+                }
+                Merge merge = (Merge) point;
+                ArrayList<Value> values = new ArrayList<Value>(merge.phiPredecessorCount());
+                Value v = null;
+                boolean createPhi = false;
+                for (EndNode end : merge.cfgPredecessors()) {
+                    Value valueAt = getValueAt(colors.get(end), valueMap, kind);
+                    if (v == null) {
+                        v = valueAt;
+                    } else if (v != valueAt) {
+                        createPhi = true;
+                    }
+                    values.add(valueAt);
+                }
+                if (createPhi) {
+                    Phi phi = new Phi(kind, merge, merge.graph());
+                    valueMap.set(point, phi);
+                    for (EndNode end : merge.cfgPredecessors()) {
+                        phi.addInput(getValueAt(colors.get(end), valueMap, kind));
+                    }
+                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + phi);
+                    return phi;
+                } else {
+                    assert v != null;
+                    valueMap.set(point, v);
+                    //System.out.println("getValueAt(" + point + ", valueMap, kind) = " + 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
+            }
+            @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);
+                    }
+                }
+            }
+            @Override
+            public Value fixPhiInput(Value input, Node color) {
+                if (newExitValues.isNew(input)) {
+                    return input;
+                }
+                NodeMap<Value> valueMap = newExitValues.get(input);
+                if (valueMap != null) {
+                    return getValueAt(color, valueMap, input.kind);
+                }
+                return input;
+            }});
+
+        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) {
+        LoopBegin loopBegin = loop.loopBegin();
+        Graph graph = loopBegin.graph();
+        NodeBitMap marked = computeLoopNodesFrom(loopBegin, from);
+        GraalCompilation compilation = GraalCompilation.compilation();
+        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);
+        }
+        clearWithState(loopBegin, marked);
+        Map<Node, Node> replacements = new HashMap<Node, Node>();
+        NodeMap<Placeholder> phis = graph.createNodeMap();
+        NodeMap<Placeholder> exits = graph.createNodeMap();
+
+        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);
+            }
+        }
+
+        for (Node n : marked) {
+            if (n instanceof Phi && ((Phi) n).merge() == loopBegin) {
+                Placeholder p = new Placeholder(graph);
+                replacements.put(n, p);
+                phis.set(n, p);
+                marked.clear(n);
+            }
+            for (Node input : n.dataInputs()) {
+                if (!marked.isMarked(input) && (!(input instanceof Phi) || ((Phi) input).merge() != loopBegin)) {
+                    replacements.put(input, input);
+                }
+            }
+        }
+
+        //GraalCompilation compilation = GraalCompilation.compilation();
+        if (compilation.compiler.isObserved()) {
+            Map<String, Object> debug = new HashMap<String, Object>();
+            debug.put("marked", marked);
+            compilation.compiler.fireCompilationEvent(new CompilationEvent(compilation, "Before addDuplicate loop#" + loopBegin.id(), loopBegin.graph(), true, false, debug));
+        }
+
+        Map<Node, Node> duplicates = graph.addDuplicate(marked, replacements);
+
+        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();
+        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);
+    }
+
+    private static NodeBitMap inOrBefore(Loop loop) {
+        Graph graph = loop.loopBegin().graph();
+        NodeBitMap inOrBefore = graph.createNodeBitMap();
+        NodeFlood work = graph.createNodeFlood();
+        NodeBitMap loopNodes = loop.nodes();
+        work.addAll(loopNodes);
+        for (Node n : work) {
+            inOrBefore.mark(n);
+            for (Node pred : n.predecessors()) {
+                work.add(pred);
+            }
+            if (n instanceof Phi) { // filter out data graph cycles
+                Phi phi = (Phi) n;
+                if (!phi.isDead()) {
+                    int backIndex = -1;
+                    Merge merge = phi.merge();
+                    if (!loopNodes.isNew(merge) && !loopNodes.isMarked(merge) && merge instanceof LoopBegin) {
+                        LoopBegin phiLoop = (LoopBegin) merge;
+                        backIndex = phiLoop.phiPredecessorIndex(phiLoop.loopEnd());
+                    }
+                    for (int i = 0; i < phi.valueCount(); i++) {
+                        if (i != backIndex) {
+                            work.add(phi.valueAt(i));
+                        }
+                    }
+                }
+            } else {
+                for (Node in : n.inputs()) {
+                    if (in != null) {
+                        work.add(in);
+                    }
+                }
+                if (n instanceof LoopBegin) {
+                    Loop p = loop.parent;
+                    boolean isParent = false;
+                    while (p != null) {
+                        if (p.loopBegin() == n) {
+                            isParent = true;
+                            break;
+                        }
+                        p = p.parent;
+                    }
+                    if (!isParent) {
+                        work.add(((LoopBegin) n).loopEnd());
+                    }
+                }
+            }
+        }
+        return inOrBefore;
+    }
+
+    private static void markWithState(Node n, NodeBitMap map) {
+        map.mark(n);
+        if (n instanceof StateSplit) {
+            FrameState stateAfter = ((StateSplit) n).stateAfter();
+            if (stateAfter != null) {
+                map.mark(stateAfter);
+            }
+        }
+    }
+
+    private static void clearWithState(Node n, NodeBitMap map) {
+        map.clear(n);
+        if (n instanceof StateSplit) {
+            FrameState stateAfter = ((StateSplit) n).stateAfter();
+            if (stateAfter != null) {
+                map.clear(stateAfter);
+            }
+        }
     }
 }
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameState.java	Fri Jul 01 18:24:04 2011 +0200
@@ -121,6 +121,10 @@
         return rethrowException;
     }
 
+    public RiMethod method() {
+        return method;
+    }
+
     /**
      * Gets a copy of this frame state.
      */
@@ -420,6 +424,15 @@
         return null;
     }
 
+    public StateSplit stateSplit() {
+        for (Node n : usages()) {
+            if (n instanceof StateSplit) {
+                return (StateSplit) n;
+            }
+        }
+        return null;
+    }
+
     /**
      * The interface implemented by a client of {@link FrameState#forEachPhi(Merge, PhiProcedure)} and
      * {@link FrameState#forEachLivePhi(Merge, PhiProcedure)}.
@@ -467,9 +480,17 @@
 
     @Override
     public String toString() {
+        return super.toString();
+    }
+
+    public String toDetailedString() {
         StringBuilder sb = new StringBuilder();
         String nl = String.format("%n");
-        sb.append("[bci: ").append(bci).append("]").append(nl);
+        sb.append("[bci: ").append(bci).append("]");
+        if (rethrowException()) {
+            sb.append(" rethrows Exception");
+        }
+        sb.append(nl);
         for (int i = 0; i < localsSize(); ++i) {
             Value value = localAt(i);
             sb.append(String.format("  local[%d] = %-8s : %s%n", i, value == null ? "bogus" : value.kind.javaName, value));
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/value/FrameStateBuilder.java	Fri Jul 01 18:24:04 2011 +0200
@@ -509,7 +509,7 @@
     }
 
     public FrameState duplicateWithoutStack(int bci) {
-        FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, true, graph);
+        FrameState frameState = new FrameState(method, bci, locals, new Value[0], 0, locks, false, graph);
         frameState.setOuterFrameState(outerFrameState());
         return frameState;
     }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotField.java	Fri Jul 01 18:24:04 2011 +0200
@@ -95,18 +95,18 @@
         return holder;
     }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof HotSpotField) {
-            HotSpotField other = (HotSpotField) obj;
-            return other.offset == offset && other.holder.equals(holder());
-        }
-        return false;
-    }
+//    @Override
+//    public boolean equals(Object obj) {
+//        if (obj instanceof HotSpotField) {
+//            HotSpotField other = (HotSpotField) obj;
+//            return other.offset == offset && other.holder.equals(holder());
+//        }
+//        return false;
+//    }
 
     @Override
     public boolean isResolved() {
-        return offset != -1;
+        return holder.isResolved();
     }
 
     @Override
@@ -130,7 +130,7 @@
 
     @Override
     public String toString() {
-        return "HotSpotField<" + holder.name() + "." + name + ">";
+        return "HotSpotField<" + holder.name() + "." + name + ":" + offset + ">";
     }
 
 }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypePrimitive.java	Fri Jul 01 18:24:04 2011 +0200
@@ -150,4 +150,8 @@
         return null;
     }
 
+    @Override
+    public RiField[] fields() {
+        return null;
+    }
 }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl.java	Fri Jul 01 18:24:04 2011 +0200
@@ -48,6 +48,7 @@
     private RiConstantPool pool;
     private RiType superType;
     private boolean superTypeSet;
+    private RiField[] fields;
 
     private HotSpotTypeResolvedImpl() {
         super(null);
@@ -222,4 +223,11 @@
         return ((HotSpotMethodResolved) method).uniqueConcreteMethod();
     }
 
+    @Override
+    public RiField[] fields() {
+        if (fields == null) {
+            fields = compiler.getVMEntries().RiType_fields(this);
+        }
+        return fields;
+    }
 }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotTypeUnresolved.java	Fri Jul 01 18:24:04 2011 +0200
@@ -201,4 +201,8 @@
         throw unresolved("uniqueConcreteMethod");
     }
 
+    @Override
+    public RiField[] fields() {
+        return null;
+    }
 }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/HotSpotXirGenerator.java	Fri Jul 01 18:24:04 2011 +0200
@@ -1043,7 +1043,6 @@
            asm.pload(CiKind.Object, objHub, object, asm.i(config.hubOffset), false);
            // if we get an exact match: continue
            asm.jneq(slowPath, objHub, hub);
-           asm.shouldNotReachHere();
 
            // -- out of line -------------------------------------------------------
            asm.bindOutOfLine(slowPath);
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntries.java	Fri Jul 01 18:24:04 2011 +0200
@@ -87,9 +87,9 @@
 
     void recordBailout(String reason);
 
-    RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved hotSpotTypeResolved);
+    RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved klass);
 
-    RiType RiType_superType(HotSpotTypeResolved hotSpotTypeResolved);
+    RiType RiType_superType(HotSpotTypeResolved klass);
 
     int getArrayLength(CiConstant array);
 
@@ -97,5 +97,7 @@
 
     RiType getRiType(CiConstant constant);
 
+    RiField[] RiType_fields(HotSpotTypeResolved klass);
+
     // Checkstyle: resume
 }
--- a/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/graal/com.oracle.max.graal.runtime/src/com/oracle/max/graal/runtime/VMEntriesNative.java	Fri Jul 01 18:24:04 2011 +0200
@@ -141,5 +141,8 @@
         return getType(o.getClass());
     }
 
+    @Override
+    public native RiField[] RiType_fields(HotSpotTypeResolved klass);
+
     // Checkstyle: resume
 }
--- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/StandardGroupOrganizer.java	Fri Jul 01 18:24:04 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>>();
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java	Fri Jul 01 18:24:04 2011 +0200
@@ -173,7 +173,7 @@
             assert nodes.get(n.getId()) == n;
             if (!scheduledNodes.contains(n)) {
                 if (noBlock == null) {
-                    noBlock = this.addBlock("no block");
+                    noBlock = this.addBlock("(no block)");
                 }
                 noBlock.addNode(n.getId());
             }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Fri Jul 01 18:24:04 2011 +0200
@@ -221,30 +221,35 @@
 
         @Override
         protected void end(String text) throws SAXException {
+            // NOTE: Some graphs intentionally don't provide blocks. Instead
+            //       they later generate the blocks from other information such
+            //       as node properties (example: ServerCompilerScheduler).
+            //       Thus, we shouldn't assign nodes that don't belong to any
+            //       block to some artificial block below unless blocks are
+            //       defined and nodes are assigned to them.
 
-            // Recover from control flow input with missing information
             if (graph.getBlocks().size() > 0) {
-                boolean blockContainsNodes = false;
+                boolean blocksContainNodes = false;
                 for (InputBlock b : graph.getBlocks()) {
                     if (b.getNodes().size() > 0) {
-                        blockContainsNodes = true;
+                        blocksContainNodes = true;
                         break;
                     }
                 }
 
-                if (!blockContainsNodes) {
+                if (!blocksContainNodes) {
                     graph.clearBlocks();
                     blockConnections.clear();
                 } else {
-                    
+                    // Blocks and their nodes defined: add other nodes to an
+                    //  artificial "no block" block
                     InputBlock noBlock = null;
-                    
                     for (InputNode n : graph.getNodes()) {
                         if (graph.getBlock(n) == null) {
                             if (noBlock == null) {
-                                noBlock = graph.addBlock("none");
+                                noBlock = graph.addBlock("(no block)");
                             }
-                            
+
                             noBlock.addNode(n.getId());
                         }
 
--- a/src/share/tools/IdealGraphVisualizer/Difference/nbproject/project.xml	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Difference/nbproject/project.xml	Fri Jul 01 18:24:04 2011 +0200
@@ -14,6 +14,14 @@
                         <specification-version>1.0</specification-version>
                     </run-dependency>
                 </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util.lookup</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>8.6.1</specification-version>
+                    </run-dependency>
+                </dependency>
             </module-dependencies>
             <public-packages>
                 <package>com.sun.hotspot.igv.difference</package>
--- a/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Difference/src/com/sun/hotspot/igv/difference/Difference.java	Fri Jul 01 18:24:04 2011 +0200
@@ -31,11 +31,13 @@
 import com.sun.hotspot.igv.data.InputNode;
 import com.sun.hotspot.igv.data.Pair;
 import com.sun.hotspot.igv.data.Property;
+import com.sun.hotspot.igv.data.services.Scheduler;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import org.openide.util.Lookup;
 
 /**
  *
@@ -84,7 +86,19 @@
         return createDiff(a, b, pairs);
     }
 
+    private static void ensureScheduled(InputGraph a) {
+        if (a.getBlocks().isEmpty()) {
+            Scheduler s = Lookup.getDefault().lookup(Scheduler.class);
+            a.clearBlocks();
+            s.schedule(a);
+            a.ensureNodesInBlocks();
+        }
+    }
+
     private static InputGraph createDiff(InputGraph a, InputGraph b, Set<NodePair> pairs) {
+        ensureScheduled(a);
+        ensureScheduled(b);
+
         Group g = new Group();
         g.setMethod(a.getGroup().getMethod());
         g.setAssembly(a.getGroup().getAssembly());
@@ -97,7 +111,10 @@
             blocksMap.put(blk, diffblk);
         }
         for (InputBlock blk : b.getBlocks()) {
-            InputBlock diffblk = graph.addBlock(blk.getName());
+            InputBlock diffblk = graph.getBlock(blk.getName());
+            if (diffblk == null) {
+                diffblk = graph.addBlock(blk.getName());
+            }
             blocksMap.put(blk, diffblk);
         }
 
@@ -117,14 +134,16 @@
             inputNodeMap.put(n, n2);
             inputNodeMap.put(nB, n2);
             graph.addNode(n2);
-            graph.setBlock(n2, blocksMap.get(a.getBlock(n)));
+            InputBlock block = blocksMap.get(a.getBlock(n));
+            block.addNode(n2.getId());
             markAsChanged(n2, n, nB);
         }
 
         for (InputNode n : nodesA) {
             InputNode n2 = new InputNode(n);
             graph.addNode(n2);
-            graph.setBlock(n2, blocksMap.get(a.getBlock(n)));
+            InputBlock block = blocksMap.get(a.getBlock(n));
+            block.addNode(n2.getId());
             markAsDeleted(n2);
             inputNodeMap.put(n, n2);
         }
@@ -132,7 +151,7 @@
         int curIndex = 0;
         for (InputNode n : nodesB) {
             InputNode n2 = new InputNode(n);
-            
+
             // Find new ID for node of b, does not change the id property
             while (graph.getNode(curIndex) != null) {
                 curIndex++;
@@ -140,7 +159,8 @@
 
             n2.setId(curIndex);
             graph.addNode(n2);
-            graph.setBlock(n2, blocksMap.get(b.getBlock(n)));
+            InputBlock block = blocksMap.get(b.getBlock(n));
+            block.addNode(n2.getId());
             markAsNew(n2);
             inputNodeMap.put(n, n2);
         }
--- a/src/share/tools/IdealGraphVisualizer/FilterWindow/src/com/sun/hotspot/igv/filterwindow/layer.xml	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/FilterWindow/src/com/sun/hotspot/igv/filterwindow/layer.xml	Fri Jul 01 18:24:04 2011 +0200
@@ -18,8 +18,11 @@
             <attr name="position" intvalue="900"/>
         </file>
     </folder>
-    <folder name="Window">
-        <file name="com-sun-hotspot-igv-coordinator-actions-FilterAction.instance"/>
+    
+    <folder name="Actions">
+        <folder name="Window">
+            <file name="com-sun-hotspot-igv-filterwindow-actions-FilterAction.instance"/>
+        </folder>
     </folder>
     <folder name="Menu">
         <folder name="Window">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalColoringFilter.java	Fri Jul 01 18:24:04 2011 +0200
@@ -0,0 +1,79 @@
+/*
+ * 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.sun.hotspot.igv.graal.filters;
+
+import com.sun.hotspot.igv.data.Properties;
+import com.sun.hotspot.igv.filter.AbstractFilter;
+import com.sun.hotspot.igv.graph.Diagram;
+import com.sun.hotspot.igv.graph.Figure;
+import java.awt.Color;
+import java.util.List;
+
+public class GraalColoringFilter extends AbstractFilter {
+    
+    private String colorName;
+
+    public GraalColoringFilter(String colorName) {
+        this.colorName = colorName;
+    }
+
+    public String getName() {
+        return "Graal Coloring Filter (" + colorName + ")";
+    }
+
+    public void apply(Diagram d) {
+        List<Figure> figures = d.getFigures();
+        int colors = 0;
+        for (Figure f : figures) {
+            Properties p = f.getProperties();
+            final String prop = p.get(colorName + "Color");
+            if (prop == null) {
+                continue;
+            }
+            try {
+                int color = Integer.parseInt(prop);
+                if (color > colors) {
+                    colors = color;
+                }
+            } catch (NumberFormatException nfe) {
+                // nothing to do
+            }
+        }
+        colors++;
+        for (Figure f : figures) {
+            Properties p = f.getProperties();
+            final String prop = p.get(colorName + "Color");
+            if (prop == null) {
+                continue;
+            }
+            try {
+                int color = Integer.parseInt(prop);
+                Color c = Color.getHSBColor((float) color / colors, 1.0f, 0.7f);
+                f.setColor(c);
+            } catch (NumberFormatException nfe) {
+                // nothing to do
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalSlotFilter.java	Fri Jul 01 18:24:04 2011 +0200
@@ -0,0 +1,66 @@
+/*
+ * 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.sun.hotspot.igv.graal.filters;
+
+import com.sun.hotspot.igv.filter.AbstractFilter;
+import com.sun.hotspot.igv.graph.Diagram;
+import com.sun.hotspot.igv.graph.Figure;
+import com.sun.hotspot.igv.graph.InputSlot;
+import com.sun.hotspot.igv.graph.OutputSlot;
+import com.sun.hotspot.igv.graph.Slot;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Filter that hides slots with no connections.
+ */
+public class GraalSlotFilter extends AbstractFilter {
+
+    public GraalSlotFilter() {
+    }
+
+    public String getName() {
+        return "Graal Slot Filter";
+    }
+
+    public void apply(Diagram d) {
+        List<Figure> figures = d.getFigures();
+        for (Figure f : figures) {
+            List<Slot> remove = new ArrayList<Slot>();
+            for (InputSlot is : f.getInputSlots()) {
+                if (is.getConnections().isEmpty()) {
+                    remove.add(is);
+                }
+            }
+            for (OutputSlot os : f.getOutputSlots()) {
+                if (os.getConnections().isEmpty()) {
+                    remove.add(os);
+                }
+            }
+            for (Slot s : remove) {
+                f.removeSlot(s);
+            }
+        }
+    }
+}
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/color.filter	Fri Jul 01 18:24:04 2011 +0200
@@ -1,9 +1,11 @@
 colorize("name", ".*", white);
-colorize("name", "StartNode|EndNode|LoopBegin|LoopEnd|Return", red);
+colorize("name", "StartNode|EndNode|LoopBegin|LoopEnd|Return", orange);
 colorize("name", "Phi:.*", magenta);
 colorize("name", "FrameState@.*", new java.awt.Color(0.5, 0.8, 1.0));
 colorize("name", "If", pink);
 colorize("name", "const.*", new java.awt.Color(0.7, 0.7, 0.7));
 colorize("name", "Local", new java.awt.Color(0.85, 0.85, 0.85));
 colorize("name", "\\+|-|\\*|/", cyan);
-colorize("name", "Comp .*", yellow);
\ No newline at end of file
+colorize("name", "Comp .*", yellow);
+
+colorize("notInOwnBlock", "true", red);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/slots.filter	Fri Jul 01 18:24:04 2011 +0200
@@ -0,0 +1,2 @@
+var f = new com.sun.hotspot.igv.graal.filters.GraalSlotFilter();
+f.apply(graph);
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Fri Jul 01 18:24:04 2011 +0200
@@ -9,5 +9,9 @@
         <file name="Graal Edge Coloring" url="filters/edgeColor.filter">
             <attr name="enabled" boolvalue="false"/>
         </file>
+        
+        <file name="Graal Slot Filter" url="filters/slots.filter">
+            <attr name="enabled" boolvalue="false"/>
+        </file>
     </folder>
 </filesystem>
--- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/genfiles.properties	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/genfiles.properties	Fri Jul 01 18:24:04 2011 +0200
@@ -1,5 +1,5 @@
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
-nbproject/build-impl.xml.data.CRC32=ac7a776e
+nbproject/build-impl.xml.data.CRC32=f0880ef0
 nbproject/build-impl.xml.script.CRC32=9388e04e
 nbproject/build-impl.xml.stylesheet.CRC32=238281d1@1.45.1
--- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/project.xml	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/nbproject/project.xml	Fri Jul 01 18:24:04 2011 +0200
@@ -63,6 +63,15 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    <code-name-base>org.netbeans.modules.diff</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.32.1.42.1</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     <code-name-base>org.openide.util</code-name-base>
                     <build-prerequisite/>
                     <compile-dependency/>
--- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.form	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.form	Fri Jul 01 18:24:04 2011 +0200
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8" ?>
+<?xml version="1.1" encoding="UTF-8" ?>
 
 <Form version="1.4" maxVersion="1.6" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
   <AuxValues>
--- a/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/GraphTextEditor/src/com/sun/hotspot/igv/graphtexteditor/TextTopComponent.java	Fri Jul 01 18:24:04 2011 +0200
@@ -24,24 +24,39 @@
 package com.sun.hotspot.igv.graphtexteditor;
 
 import com.sun.hotspot.igv.data.ChangedListener;
+import com.sun.hotspot.igv.data.Properties;
 import com.sun.hotspot.igv.texteditor.*;
 import com.sun.hotspot.igv.data.InputGraph;
 import com.sun.hotspot.igv.data.Pair;
+import com.sun.hotspot.igv.data.Property;
 import com.sun.hotspot.igv.graph.Diagram;
 import com.sun.hotspot.igv.graph.services.DiagramProvider;
 import com.sun.hotspot.igv.graphtotext.services.GraphToTextConverter;
 import com.sun.hotspot.igv.selectioncoordinator.SelectionCoordinator;
+import com.sun.hotspot.igv.structuredtext.MultiElement;
 import com.sun.hotspot.igv.structuredtext.StructuredText;
 import com.sun.hotspot.igv.util.LookupHistory;
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
 import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.io.IOException;
 import java.io.Serializable;
+import java.io.StringReader;
 import java.util.Collection;
 import java.util.logging.Logger;
+import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JSplitPane;
+import javax.swing.JToolBar;
+import org.netbeans.api.diff.Diff;
+import org.netbeans.api.diff.DiffView;
+import org.netbeans.api.diff.StreamSource;
 import org.openide.util.Lookup;
 import org.openide.util.LookupEvent;
 import org.openide.util.LookupListener;
@@ -52,6 +67,7 @@
 
 /**
  * @author Thomas Wuerthinger
+ * @author Peter Hofer
  */
 final class TextTopComponent extends TopComponent implements LookupListener {
 
@@ -65,12 +81,17 @@
     private JSplitPane splitPane;
     private CardLayout cardLayout;
     private JPanel cardLayoutPanel;
-    private boolean firstTimeSlider = true;
+    private JComboBox sourceCombo;
+    private boolean firstTimeSplitter = true;
+    private JPanel textDiffPanel;
 
+    private static final String TWO_GRAPHS_TEXT_DIFF = "twoGraphsTextDiff";
     private static final String TWO_GRAPHS = "twoGraphs";
     private static final String ONE_GRAPH = "oneGraph";
     private static final String NO_GRAPH = "noGraph";
 
+    private static final String GRAPH_TEXT_REPRESENTATION = "< Graph Text Representation >";
+
     private DiagramProvider currentDiagramProvider;
 
     private TextTopComponent() {
@@ -78,16 +99,28 @@
         setName(NbBundle.getMessage(TextTopComponent.class, "CTL_TextTopComponent"));
         setToolTipText(NbBundle.getMessage(TextTopComponent.class, "HINT_TextTopComponent"));
 
+        setLayout(new BorderLayout());
+
+        // Selector for displayed data
+        JToolBar sourceSelectBar = new JToolBar();
+        sourceSelectBar.setLayout(new BorderLayout());
+        sourceSelectBar.setFloatable(false);
+        sourceSelectBar.add(new JLabel("Show: "), BorderLayout.WEST);
+        sourceCombo = new JComboBox();
+        sourceCombo.addItem(GRAPH_TEXT_REPRESENTATION);
+        sourceCombo.addItemListener(sourceSelectionListener);
+        sourceSelectBar.add(sourceCombo, BorderLayout.CENTER);
+        add(sourceSelectBar, BorderLayout.NORTH);
+
         // Card layout for three different views.
         cardLayout = new CardLayout();
         cardLayoutPanel = new JPanel(cardLayout);
-        this.setLayout(new BorderLayout());
-        this.add(cardLayoutPanel, BorderLayout.CENTER);
+        add(cardLayoutPanel, BorderLayout.CENTER);
 
         // No graph selected.
-        JLabel noGraphLabel = new JLabel("No graph opened");
-        noGraphLabel.setBackground(Color.red);
-        //noGraphPanel.add(noGraphLabel);
+        JLabel noGraphLabel = new JLabel("No graph open.", JLabel.CENTER);
+        noGraphLabel.setOpaque(true);
+        noGraphLabel.setBackground(Color.WHITE);
         cardLayoutPanel.add(noGraphLabel, NO_GRAPH);
 
         // Single graph selected.
@@ -97,10 +130,31 @@
         // Graph difference => show split pane with two graphs.
         splitPane = new JSplitPane();
         leftEditor = new TextEditor();
-        splitPane.setLeftComponent(leftEditor.getComponent());
         rightEditor = new TextEditor();
-        splitPane.setRightComponent(rightEditor.getComponent());
+        // Work around a problem with JSplitPane and the NetBeans editor:
+        // setDividerLocation() doesn't work when the split pane has not been
+        // layouted and painted yet. JSplitPane then initially uses a tiny width
+        // for the left editor component, which causes the editor to calculate
+        // invalid offsets and constantly throw exceptions, particularly on
+        // mouse events. Thus, defer adding the two components and setting the
+        // divider's location.
+        splitPane.addComponentListener(new ComponentAdapter() {
+            @Override
+            public void componentResized(ComponentEvent e) {
+                if (firstTimeSplitter && splitPane.getWidth() > 0) {
+                    splitPane.setLeftComponent(leftEditor.getComponent());
+                    splitPane.setRightComponent(rightEditor.getComponent());
+                    splitPane.setDividerLocation(0.5);
+                    firstTimeSplitter = false;
+                }
+            }
+        });
         cardLayoutPanel.add(splitPane, TWO_GRAPHS);
+        
+        // Text difference => NetBeans diff view
+        // Diff component is created and added on demand
+        textDiffPanel = new JPanel(new BorderLayout());
+        cardLayoutPanel.add(textDiffPanel, TWO_GRAPHS_TEXT_DIFF);
     }
 
 
@@ -129,23 +183,104 @@
         return text;
     }
 
-    private void updateDiagram(Diagram diagram) {
+    private StructuredText createStructuredPlainText(String name, String text) {
+        StructuredText structured = new StructuredText(name);
+        MultiElement multi = new MultiElement();
+        multi.print(text);
+        structured.addChild(multi);
+        return structured;
+    }
 
+    private ItemListener sourceSelectionListener = new ItemListener() {
+        public void itemStateChanged(ItemEvent e) {
+            if (e.getStateChange() == ItemEvent.SELECTED) {
+                if (e.getItem() == GRAPH_TEXT_REPRESENTATION) {
+                    displayDiagram(lastDiagram);
+                } else {
+                    displayGroupProperty(lastDiagram, (String) e.getItem());
+                }
+            }
+        }
+    };
+
+    private void setDiagram(Diagram diagram) {
         if (diagram == lastDiagram) {
             // No change => return.
             return;
         }
-
         lastDiagram = diagram;
 
+        // Rebuild combobox choices
+        Object selection = sourceCombo.getSelectedItem();
+        sourceCombo.removeAllItems();
+        sourceCombo.addItem(GRAPH_TEXT_REPRESENTATION);
+        if (diagram != null) {
+            if (diagram.getGraph().getSourceGraphs() != null) {
+                // Diff graph with source graphs with possibly different groups:
+                // show properties from both graphs
+                Pair<InputGraph, InputGraph> sourceGraphs = diagram.getGraph().getSourceGraphs();
+                Properties props = new Properties(sourceGraphs.getLeft().getGroup().getProperties());
+                if (sourceGraphs.getLeft().getGroup() != sourceGraphs.getRight().getGroup()) {
+                    props.add(sourceGraphs.getRight().getGroup().getProperties());
+                }
+                for (Property p : props) {
+                    sourceCombo.addItem(p.getName());
+                }
+            } else {
+                // Single graph
+                for (Property p : diagram.getGraph().getGroup().getProperties()) {
+                    sourceCombo.addItem(p.getName());
+                }
+            }
+        }
+        // NOTE: The following triggers a display update.
+        sourceCombo.setSelectedItem(selection);
+        if (sourceCombo.getSelectedItem() == null) {
+            // previously selected property doesn't exist in new graph's group:
+            // default to show graph representation
+            sourceCombo.setSelectedItem(GRAPH_TEXT_REPRESENTATION);
+        }
+    }
+
+    private void displayGroupProperty(Diagram diagram, String property) {
+        if (diagram == null) {
+            showCard(NO_GRAPH);
+        } else if (diagram.getGraph().getSourceGraphs() != null) {
+            showCard(TWO_GRAPHS_TEXT_DIFF);
+            textDiffPanel.removeAll();
+            try {
+                Pair<InputGraph, InputGraph> sourceGraphs = diagram.getGraph().getSourceGraphs();
+
+                String ltext = sourceGraphs.getLeft().getGroup().getProperties().get(property);
+                if (ltext == null) {
+                    ltext = "";
+                }
+                StreamSource leftsrc = StreamSource.createSource("left", sourceGraphs.getLeft().getName(), "text/plain", new StringReader(ltext));
+
+                String rtext = sourceGraphs.getRight().getGroup().getProperties().get(property);
+                if (rtext == null) {
+                    rtext = "";
+                }
+                StreamSource rightsrc = StreamSource.createSource("right", sourceGraphs.getRight().getName(), "text/plain", new StringReader(rtext));
+
+                DiffView view = Diff.getDefault().createDiff(leftsrc, rightsrc);
+                textDiffPanel.add(view.getComponent(), BorderLayout.CENTER);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            textDiffPanel.revalidate(); // required when card was visible before
+        } else {
+            showCard(ONE_GRAPH);
+            String text = diagram.getGraph().getGroup().getProperties().get(property);
+            singleEditor.setStructuredText(createStructuredPlainText(diagram.getGraph().getName(), text));
+        }
+    }
+
+    private void displayDiagram(Diagram diagram) {
         if (diagram == null) {
             showCard(NO_GRAPH);
         } else if (diagram.getGraph().getSourceGraphs() != null) {
             showCard(TWO_GRAPHS);
-            if (firstTimeSlider) {
-                splitPane.setDividerLocation(0.5);
-            }
-            firstTimeSlider = false;
             Pair<InputGraph, InputGraph> graphs = diagram.getGraph().getSourceGraphs();
             leftEditor.setStructuredText(convert(graphs.getLeft(), diagram));
             rightEditor.setStructuredText(convert(graphs.getRight(), diagram));
@@ -161,17 +296,16 @@
             SelectionCoordinator.getInstance().getHighlightedChangedEvent().fire();
         }
     }
-    
+
     private ChangedListener<DiagramProvider> diagramChangedListener = new ChangedListener<DiagramProvider>() {
 
         public void changed(DiagramProvider source) {
-            updateDiagram(source.getDiagram());
+            setDiagram(source.getDiagram());
         }
         
     };
 
-    private void updateDiagramProvider(DiagramProvider provider) {
-
+    private void setDiagramProvider(DiagramProvider provider) {
         if (provider == currentDiagramProvider) {
             return;
         }
@@ -184,9 +318,9 @@
 
         if (currentDiagramProvider != null) {
             currentDiagramProvider.getChangedEvent().addListener(diagramChangedListener);
-            updateDiagram(currentDiagramProvider.getDiagram());
+            setDiagram(currentDiagramProvider.getDiagram());
         } else {
-            updateDiagram(null);
+            setDiagram(null);
         }
     }
 
@@ -201,7 +335,7 @@
             p = LookupHistory.getLast(DiagramProvider.class);
         }
 
-        updateDiagramProvider(p);
+        setDiagramProvider(p);
     }
 
     /** This method is called from within the constructor to
@@ -258,7 +392,7 @@
     public void componentOpened() {
 
         DiagramProvider p = LookupHistory.getLast(DiagramProvider.class);
-        updateDiagramProvider(p);
+        setDiagramProvider(p);
 
         Lookup.Template<DiagramProvider> tpl = new Lookup.Template<DiagramProvider>(DiagramProvider.class);
         result = Utilities.actionsGlobalContext().lookup(tpl);
@@ -269,7 +403,7 @@
     public void componentClosed() {
         result.removeLookupListener(this);
         result = null;
-        updateDiagramProvider(null);
+        setDiagramProvider(null);
     }
 
     /** replaces this in object stream */
--- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Fri Jul 01 18:24:04 2011 +0200
@@ -530,9 +530,11 @@
         }
     };
     private static final Comparator<LayoutNode> nodeProcessingDownComparator = new Comparator<LayoutNode>() {
-
         public int compare(LayoutNode n1, LayoutNode n2) {
             if (n1.vertex == null) {
+                if (n2.vertex == null) {
+                    return 0;
+                }
                 return -1;
             }
             if (n2.vertex == null) {
@@ -545,6 +547,9 @@
 
         public int compare(LayoutNode n1, LayoutNode n2) {
             if (n1.vertex == null) {
+                if (n2.vertex == null) {
+                    return 0;
+                }
                 return -1;
             }
             if (n2.vertex == null) {
--- a/src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/ServerCompiler/src/com/sun/hotspot/igv/servercompiler/ServerCompilerScheduler.java	Fri Jul 01 18:24:04 2011 +0200
@@ -212,7 +212,7 @@
             for (InputNode n : graph.getNodes()) {
                 if (graph.getBlock(n) == null) {
                     if (noBlock == null) {
-                        noBlock = graph.addBlock("none");
+                        noBlock = graph.addBlock("(no block)");
                         blocks.add(noBlock);
                     }
                     
--- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/Bundle.properties	Fri Jul 01 18:15:05 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-OpenIDE-Module-Name=Text Editor
--- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/layer.xml	Fri Jul 01 18:15:05 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
-<filesystem>
-    <attr name="Editors\Preferences\Defaults\org-netbeans-modules-editor-preferences-mac.xml\position" intvalue="200"/>
-    <attr name="Editors\Preferences\Defaults\org-netbeans-modules-editor-preferences.xml\position" intvalue="100"/>
-    <folder name="Editors">
-        <folder name="Preferences">
-            <folder name="Defaults">
-                <file name="at-ssw-visualizer-texteditor-preferences.xml" url="preferences.xml">
-                    <attr name="position" intvalue="300"/>
-                </file>
-            </folder>
-        </folder>
-    </folder>
-</filesystem>
--- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/classes/at/ssw/visualizer/texteditor/preferences.xml	Fri Jul 01 18:15:05 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE editor-preferences PUBLIC "-//NetBeans//DTD Editor Preferences 1.0//EN" "http://www.netbeans.org/dtds/EditorPreferences-1_0.dtd">
-
-<editor-preferences>
-    <entry name="code-folding-enable" value="true" javaType="java.lang.Boolean" />
-</editor-preferences>
--- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/depcache/dependencies.txt	Fri Jul 01 18:15:05 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,282 +0,0 @@
-||:at.ssw.visualizer.texteditor.Editor
-at.ssw.visualizer.core.selection.SelectionManager
-at.ssw.visualizer.core.selection.SelectionProvider
-org.openide.text.CloneableEditor
-javax.swing.JEditorPane
-at.ssw.visualizer.texteditor.Editor$2
-at.ssw.visualizer.texteditor.Editor$1
-at.ssw.visualizer.core.selection.Selection
-at.ssw.visualizer.texteditor.Editor
-at.ssw.visualizer.texteditor.EditorSupport
-||:at.ssw.visualizer.texteditor.EditorSupport
-java.lang.StringBuilder
-java.lang.UnsupportedOperationException
-org.openide.windows.CloneableOpenSupport$Env
-org.openide.text.CloneableEditorSupport
-at.ssw.visualizer.texteditor.EditorSupport$Env
-javax.swing.text.StyledDocument
-org.openide.windows.CloneableOpenSupport
-at.ssw.visualizer.texteditor.model.Text
-org.openide.cookies.EditorCookie$Observable
-com.sun.hotspot.igv.data.InputGraph
-org.openide.cookies.EditCookie
-org.openide.cookies.EditorCookie
-org.openide.text.CloneableEditorSupport$Env
-at.ssw.visualizer.texteditor.EditorSupport
-com.sun.hotspot.igv.data.Group
-||:at.ssw.visualizer.texteditor.fold.FoldManager$SideBarFactory
-java.lang.Object
-at.ssw.visualizer.texteditor.fold.FoldManager$SideBarFactory
-org.netbeans.editor.SideBarFactory
-at.ssw.visualizer.texteditor.fold.FoldManager
-org.netbeans.editor.CodeFoldingSideBar
-||:at.ssw.visualizer.texteditor.model.FoldingRegion
-at.ssw.visualizer.texteditor.model.FoldingRegion
-at.ssw.visualizer.texteditor.model.TextRegion
-||:at.ssw.visualizer.texteditor.tooltip.StyledToolTip
-java.awt.Color
-javax.swing.border.LineBorder
-java.awt.BorderLayout
-java.lang.StringBuilder
-java.awt.Dimension
-at.ssw.visualizer.texteditor.tooltip.StyledToolTip
-javax.swing.JEditorPane
-javax.swing.JPanel
-||:at.ssw.visualizer.texteditor.model.TextRegion
-java.lang.Object
-at.ssw.visualizer.texteditor.model.TextRegion
-||:at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent$1
-java.lang.Object
-at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent
-at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent$1
-javax.swing.event.ChangeListener
-||:at.ssw.visualizer.texteditor.model.TextBuilder
-java.lang.StringBuilder
-com.sun.hotspot.igv.data.InputBlock
-java.util.HashSet
-java.util.Set
-java.util.List
-java.util.ArrayList
-at.ssw.visualizer.texteditor.model.Text
-at.ssw.visualizer.texteditor.model.TextBuilder
-java.util.Iterator
-java.util.HashMap
-java.util.Map
-[Lat.ssw.visualizer.texteditor.model.FoldingRegion;
-at.ssw.visualizer.texteditor.model.FoldingRegion
-java.lang.Object
-java.lang.String
-||:at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent
-at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent
-javax.swing.JScrollPane
-at.ssw.visualizer.core.selection.SelectionManager
-javax.swing.JEditorPane
-javax.swing.BorderFactory
-java.awt.BorderLayout
-com.sun.hotspot.igv.data.InputGraph
-[Lcom.sun.hotspot.igv.data.InputBlock;
-at.ssw.visualizer.core.selection.Selection
-org.openide.windows.TopComponent
-at.ssw.visualizer.texteditor.view.AbstractTextViewTopComponent$1
-java.util.Arrays
-||:at.ssw.visualizer.texteditor.tooltip.ToolTipAction
-at.ssw.visualizer.texteditor.model.Scanner
-org.netbeans.editor.PopupManager
-org.netbeans.editor.Utilities
-org.netbeans.editor.TokenID
-org.netbeans.editor.PopupManager$HorizontalBounds
-org.netbeans.modules.editor.NbEditorKit$NbBuildToolTipAction
-org.netbeans.editor.BaseDocument
-org.netbeans.editor.EditorUI
-at.ssw.visualizer.texteditor.model.Text
-javax.swing.plaf.TextUI
-java.awt.event.MouseEvent
-org.netbeans.modules.editor.NbEditorKit
-org.netbeans.editor.ext.ToolTipSupport
-at.ssw.visualizer.texteditor.tooltip.ToolTipAction
-javax.swing.text.JTextComponent
-at.ssw.visualizer.texteditor.tooltip.StyledToolTip
-org.netbeans.editor.PopupManager$Placement
-||:at.ssw.visualizer.texteditor.fold.FoldManager$FoldManagerFactory
-java.lang.Object
-org.netbeans.spi.editor.fold.FoldManagerFactory
-at.ssw.visualizer.texteditor.fold.FoldManager$FoldManagerFactory
-at.ssw.visualizer.texteditor.fold.FoldManager
-||:at.ssw.visualizer.core.selection.Selection
-[Ljavax.swing.event.ChangeListener;
-at.ssw.visualizer.core.selection.Selection$1
-javax.swing.event.ChangeListener
-java.util.List
-java.util.ArrayList
-at.ssw.visualizer.core.selection.SelectionManager
-java.lang.Class
-java.util.HashMap
-java.util.Map
-javax.swing.event.ChangeEvent
-at.ssw.visualizer.core.selection.Selection
-java.lang.Object
-javax.swing.Timer
-||:at.ssw.visualizer.texteditor.model.BlockRegion
-at.ssw.visualizer.texteditor.model.BlockRegion
-at.ssw.visualizer.texteditor.model.TextRegion
-||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer$HighlightsLayerFactory
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer
-at.ssw.visualizer.texteditor.model.Text
-org.netbeans.spi.editor.highlighting.HighlightsLayerFactory
-org.netbeans.spi.editor.highlighting.HighlightsLayer
-java.lang.Object
-javax.swing.text.Document
-org.netbeans.spi.editor.highlighting.ZOrder
-org.netbeans.spi.editor.highlighting.HighlightsLayerFactory$Context
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer$HighlightsLayerFactory
-||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer
-javax.swing.text.JTextComponent
-org.netbeans.spi.editor.highlighting.support.AbstractHighlightsContainer
-org.netbeans.api.editor.mimelookup.MimeLookup
-org.openide.util.WeakListeners
-org.netbeans.api.editor.mimelookup.MimePath
-javax.swing.text.SimpleAttributeSet
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer$HighlightsLayerFactory
-org.openide.util.Lookup
-javax.swing.event.CaretListener
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer
-at.ssw.visualizer.texteditor.model.Text
-at.ssw.visualizer.texteditor.model.Scanner
-org.netbeans.api.editor.settings.FontColorSettings
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer$1
-javax.swing.text.Caret
-org.netbeans.editor.TokenID
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer$RegionSequence
-javax.swing.text.Document
-||:at.ssw.visualizer.core.selection.Selection$1
-java.lang.Object
-at.ssw.visualizer.core.selection.Selection
-at.ssw.visualizer.core.selection.Selection$1
-java.awt.event.ActionListener
-||:at.ssw.visualizer.texteditor.model.HoverParser
-java.lang.Object
-java.util.Iterator
-java.lang.String
-java.lang.StringBuilder
-java.lang.UnsupportedOperationException
-at.ssw.visualizer.texteditor.model.HoverParser
-||:at.ssw.visualizer.texteditor.Editor$2
-at.ssw.visualizer.texteditor.Editor
-java.util.ArrayList
-javax.swing.event.CaretEvent
-java.util.List
-[Lcom.sun.hotspot.igv.data.InputBlock;
-com.sun.hotspot.igv.data.InputBlock
-java.util.Map
-java.util.Collection
-at.ssw.visualizer.core.selection.Selection
-at.ssw.visualizer.texteditor.model.BlockRegion
-java.util.Iterator
-javax.swing.event.CaretListener
-at.ssw.visualizer.texteditor.Editor$2
-at.ssw.visualizer.texteditor.model.Text
-java.lang.Math
-java.lang.Object
-javax.swing.JEditorPane
-javax.swing.text.Document
-||:at.ssw.visualizer.texteditor.EditorSupport$Env
-java.lang.UnsupportedOperationException
-org.openide.text.CloneableEditorSupport
-at.ssw.visualizer.texteditor.EditorSupport$Env
-java.beans.VetoableChangeSupport
-at.ssw.visualizer.texteditor.model.Text
-java.io.ByteArrayInputStream
-java.io.IOException
-java.lang.Object
-at.ssw.visualizer.texteditor.EditorSupport
-org.openide.text.CloneableEditorSupport$Env
-java.beans.PropertyChangeSupport
-java.lang.String
-||:at.ssw.visualizer.texteditor.Editor$1
-java.lang.Math
-at.ssw.visualizer.texteditor.model.BlockRegion
-javax.swing.event.ChangeListener
-at.ssw.visualizer.texteditor.model.Text
-javax.swing.JEditorPane
-java.util.Map
-[Lcom.sun.hotspot.igv.data.InputBlock;
-at.ssw.visualizer.texteditor.Editor$1
-at.ssw.visualizer.core.selection.Selection
-java.lang.Object
-javax.swing.text.Document
-at.ssw.visualizer.texteditor.Editor
-java.util.Arrays
-||:at.ssw.visualizer.texteditor.model.Text
-java.lang.String
-[Lat.ssw.visualizer.texteditor.model.TextRegion;
-java.lang.Object
-java.util.Iterator
-java.util.Map
-java.util.Set
-at.ssw.visualizer.texteditor.model.Text
-at.ssw.visualizer.texteditor.model.TextRegion
-||:at.ssw.visualizer.core.selection.SelectionProvider
-java.lang.Object
-at.ssw.visualizer.core.selection.SelectionProvider
-||:at.ssw.visualizer.texteditor.EditorKit
-javax.swing.Action
-at.ssw.visualizer.texteditor.tooltip.ToolTipAction
-at.ssw.visualizer.texteditor.EditorKit
-org.netbeans.modules.editor.NbEditorKit
-javax.swing.text.TextAction
-||:at.ssw.visualizer.core.selection.SelectionManager
-at.ssw.visualizer.core.selection.Selection
-java.lang.Object
-at.ssw.visualizer.core.selection.SelectionManager
-||:at.ssw.visualizer.texteditor.model.Scanner
-at.ssw.visualizer.texteditor.model.Scanner
-javax.swing.text.BadLocationException
-java.lang.Math
-java.util.Set
-java.util.BitSet
-java.lang.Class
-java.util.logging.Level
-java.util.logging.Logger
-javax.swing.text.Document
-java.lang.String
-org.netbeans.editor.Syntax
-||:at.ssw.visualizer.texteditor.fold.FoldManager
-at.ssw.visualizer.texteditor.fold.FoldManager$FoldManagerFactory
-javax.swing.text.BadLocationException
-at.ssw.visualizer.texteditor.fold.FoldManager
-org.netbeans.api.editor.fold.FoldType
-at.ssw.visualizer.texteditor.fold.FoldManager$SideBarFactory
-org.netbeans.spi.editor.fold.FoldManager
-at.ssw.visualizer.texteditor.model.Text
-java.lang.Class
-java.util.logging.Level
-java.util.logging.Logger
-at.ssw.visualizer.texteditor.model.FoldingRegion
-java.lang.Object
-org.netbeans.api.editor.fold.FoldHierarchy
-javax.swing.text.Document
-javax.swing.text.JTextComponent
-org.netbeans.spi.editor.fold.FoldOperation
-||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer$1
-java.lang.Object
-javax.swing.event.CaretListener
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer$1
-javax.swing.text.Document
-||:at.ssw.visualizer.texteditor.hyperlink.HyperlinkProvider
-at.ssw.visualizer.texteditor.model.Scanner
-org.netbeans.editor.Utilities
-at.ssw.visualizer.texteditor.hyperlink.HyperlinkProvider
-org.netbeans.editor.TokenID
-org.netbeans.lib.editor.hyperlink.spi.HyperlinkProvider
-at.ssw.visualizer.texteditor.model.Text
-java.lang.Object
-javax.swing.text.Document
-at.ssw.visualizer.texteditor.model.TextRegion
-javax.swing.text.JTextComponent
-||:at.ssw.visualizer.texteditor.highlight.HighlightsContainer$RegionSequence
-java.lang.Object
-org.netbeans.spi.editor.highlighting.HighlightsSequence
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer
-at.ssw.visualizer.texteditor.highlight.HighlightsContainer$RegionSequence
-at.ssw.visualizer.texteditor.model.TextRegion
--- a/src/share/tools/IdealGraphVisualizer/Text Editor/build/no-license.txt	Fri Jul 01 18:15:05 2011 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-[NO LICENSE SPECIFIED]
\ No newline at end of file
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Fri Jul 01 18:24:04 2011 +0200
@@ -60,6 +60,7 @@
 import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -1141,11 +1142,9 @@
         Rectangle r = w.getBounds();
         Point p = w.getLocation();
         centerRectangle(new Rectangle(p.x, p.y, r.width, r.height));
-
     }
 
     public void gotoFigure(final Figure f) {
-
         if (!isVisible(f)) {
             showFigure(f);
         }
@@ -1153,7 +1152,7 @@
         FigureWidget fw = getWidget(f);
         if (fw != null) {
             centerWidget(fw);
-            getModel().setSelectedNodes(f.getSource().getSourceNodesAsSet());
+            setSelection(Arrays.asList(f));
         }
     }
 
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandPredecessorsAction.java	Fri Jul 01 18:24:04 2011 +0200
@@ -41,7 +41,7 @@
     }
 
     public String getName() {
-        return "Expand Predecessors";
+        return "Expand Above";
     }
 
     @Override
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/actions/ExpandSuccessorsAction.java	Fri Jul 01 18:24:04 2011 +0200
@@ -41,7 +41,7 @@
     }
 
     public String getName() {
-        return "Expand Successors";
+        return "Expand Below";
     }
 
     @Override
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Fri Jul 01 18:24:04 2011 +0200
@@ -271,10 +271,10 @@
     public JPopupMenu getPopupMenu(Widget widget, Point point) {
         JPopupMenu m = diagramScene.createPopupMenu();
 
-        JMenu predecessors = new JMenu("Predecessors");
+        JMenu predecessors = new JMenu("Nodes Above");
         addFigureToSubMenu(predecessors, getFigure(), false, DEPTH);
 
-        JMenu successors = new JMenu("Successors");
+        JMenu successors = new JMenu("Nodes Below");
         addFigureToSubMenu(successors, getFigure(), true, DEPTH);
 
         m.addSeparator();
@@ -308,14 +308,13 @@
     }
 
     public void addFigureToMenu(JMenu m, final Figure f, boolean successor, int depth) {
-
         Action a = diagramScene.createGotoAction(f);
         m.add(a);
 
         if (depth > 0) {
-            String name = "Predecessors";
+            String name = "Nodes Above";
             if (successor) {
-                name = "Successors";
+                name = "Nodes Below";
             }
 
             JMenu subMenu = new JMenu(name);
--- a/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/tools/IdealGraphVisualizer/nbproject/platform.properties	Fri Jul 01 18:24:04 2011 +0200
@@ -56,21 +56,16 @@
     org.netbeans.modules.dbapi,\
     org.netbeans.modules.defaults,\
     org.netbeans.modules.derby,\
-    org.netbeans.modules.diff,\
     org.netbeans.modules.dlight.nativeexecution,\
     org.netbeans.modules.dlight.terminal,\
     org.netbeans.modules.editor.bookmarks,\
     org.netbeans.modules.editor.bracesmatching,\
     org.netbeans.modules.editor.codetemplates,\
     org.netbeans.modules.editor.completion,\
-    org.netbeans.modules.editor.errorstripe,\
-    org.netbeans.modules.editor.errorstripe.api,\
     org.netbeans.modules.editor.guards,\
     org.netbeans.modules.editor.indent.project,\
     org.netbeans.modules.editor.kit,\
     org.netbeans.modules.editor.macros,\
-    org.netbeans.modules.editor.plain,\
-    org.netbeans.modules.editor.plain.lib,\
     org.netbeans.modules.editor.structure,\
     org.netbeans.modules.extbrowser,\
     org.netbeans.modules.extexecution,\
@@ -105,13 +100,11 @@
     org.netbeans.modules.lexer.nbbridge,\
     org.netbeans.modules.localhistory,\
     org.netbeans.modules.mercurial,\
-    org.netbeans.modules.options.editor,\
     org.netbeans.modules.parsing.api,\
     org.netbeans.modules.parsing.lucene,\
     org.netbeans.modules.print.editor,\
     org.netbeans.modules.project.ant,\
     org.netbeans.modules.project.libraries,\
-    org.netbeans.modules.projectapi,\
     org.netbeans.modules.projectui,\
     org.netbeans.modules.projectui.buildmenu,\
     org.netbeans.modules.projectuiapi,\
--- a/src/share/vm/classfile/systemDictionary.hpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/classfile/systemDictionary.hpp	Fri Jul 01 18:24:04 2011 +0200
@@ -209,10 +209,12 @@
   template(CiRegister_klass,             com_sun_cri_ci_CiRegister,                                 Opt) \
   template(CiCodePos_klass,              com_sun_cri_ci_CiCodePos,                                  Opt) \
   template(CiConstant_klass,             com_sun_cri_ci_CiConstant,                                 Opt) \
+  template(CiVirtualObject_klass,        com_sun_cri_ci_CiVirtualObject,                            Opt) \
   template(CiKind_klass,                 com_sun_cri_ci_CiKind,                                     Opt) \
   template(CiRuntimeCall_klass,          com_sun_cri_ci_CiRuntimeCall,                              Opt) \
   template(RiMethod_klass,               com_sun_cri_ri_RiMethod,                                   Opt) \
   template(RiType_klass,                 com_sun_cri_ri_RiType,                                     Opt) \
+  template(RiField_klass,                com_sun_cri_ri_RiField,                                    Opt) \
   template(RiExceptionHandler_klass,     com_sun_cri_ri_RiExceptionHandler,                         Opt) \
   template(RiTypeProfile_klass,          com_sun_cri_ri_RiTypeProfile,                              Opt) \
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri Jul 01 18:24:04 2011 +0200
@@ -258,18 +258,18 @@
   LP64_ONLY( do_alias(machine_word_signature,         long_signature) )                           \
                                                                                                                         \
   /* support for graal */                                                                                               \
-  template(com_sun_hotspot_graal_VMExits,               "com/oracle/max/graal/runtime/VMExits")                         \
+  template(com_sun_hotspot_graal_VMExits,             "com/oracle/max/graal/runtime/VMExits")                           \
   template(com_sun_hotspot_graal_HotSpotMethodResolved, "com/oracle/max/graal/runtime/HotSpotMethodResolvedImpl")       \
-  template(com_sun_hotspot_graal_HotSpotTargetMethod,   "com/oracle/max/graal/runtime/HotSpotTargetMethod")             \
-  template(com_sun_hotspot_graal_HotSpotField,          "com/oracle/max/graal/runtime/HotSpotField")                    \
-  template(com_sun_graal_graalOptions,                    "com/sun/graal/graalOptions")                                 \
-  template(com_sun_hotspot_graal_HotSpotOptions,        "com/oracle/max/graal/runtime/HotSpotOptions")                  \
-  template(com_sun_hotspot_graal_HotSpotTypeResolved,   "com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl")         \
-  template(com_sun_hotspot_graal_HotSpotType,           "com/oracle/max/graal/runtime/HotSpotType")                     \
+  template(com_sun_hotspot_graal_HotSpotTargetMethod, "com/oracle/max/graal/runtime/HotSpotTargetMethod")               \
+  template(com_sun_hotspot_graal_HotSpotField,        "com/oracle/max/graal/runtime/HotSpotField")                      \
+  template(com_sun_graal_graalOptions,                "com/sun/graal/graalOptions")                                     \
+  template(com_sun_hotspot_graal_HotSpotOptions,      "com/oracle/max/graal/runtime/HotSpotOptions")                    \
+  template(com_sun_hotspot_graal_HotSpotTypeResolved, "com/oracle/max/graal/runtime/HotSpotTypeResolvedImpl")           \
+  template(com_sun_hotspot_graal_HotSpotType,         "com/oracle/max/graal/runtime/HotSpotType")                       \
   template(com_sun_hotspot_graal_HotSpotExceptionHandler,"com/oracle/max/graal/runtime/HotSpotExceptionHandler")        \
-  template(com_sun_hotspot_graal_HotSpotProxy,          "com/oracle/max/graal/runtime/HotSpotProxy")                    \
-  template(com_sun_hotspot_graal_Compiler,              "com/oracle/max/graal/runtime/Compiler")                        \
-  template(com_sun_hotspot_graal_CompilerImpl,          "com/oracle/max/graal/runtime/CompilerImpl")                    \
+  template(com_sun_hotspot_graal_HotSpotProxy,        "com/oracle/max/graal/runtime/HotSpotProxy")                      \
+  template(com_sun_hotspot_graal_Compiler,            "com/oracle/max/graal/runtime/Compiler")                          \
+  template(com_sun_hotspot_graal_CompilerImpl,        "com/oracle/max/graal/runtime/CompilerImpl")                      \
   template(com_sun_cri_ri_RiMethod,                   "com/sun/cri/ri/RiMethod")                                        \
   template(com_sun_cri_ri_RiField,                    "com/sun/cri/ri/RiField")                                         \
   template(com_sun_cri_ri_RiType,                     "com/sun/cri/ri/RiType")                                          \
@@ -278,7 +278,7 @@
   template(com_sun_cri_ri_RiExceptionHandler,         "com/sun/cri/ri/RiExceptionHandler")                              \
   template(com_sun_cri_ci_CiAssumptions,              "com/sun/cri/ci/CiAssumptions")                                   \
   template(com_sun_cri_ci_CiAssumptions_ConcreteSubtype, "com/sun/cri/ci/CiAssumptions$ConcreteSubtype")                \
-  template(com_sun_cri_ci_CiAssumptions_ConcreteMethod,  "com/sun/cri/ci/CiAssumptions$ConcreteMethod")                 \
+  template(com_sun_cri_ci_CiAssumptions_ConcreteMethod, "com/sun/cri/ci/CiAssumptions$ConcreteMethod")                  \
   template(com_sun_cri_ci_CiTargetMethod,             "com/sun/cri/ci/CiTargetMethod")                                  \
   template(com_sun_cri_ci_CiTargetMethod_Site,        "com/sun/cri/ci/CiTargetMethod$Site")                             \
   template(com_sun_cri_ci_CiTargetMethod_Call,        "com/sun/cri/ci/CiTargetMethod$Call")                             \
@@ -295,6 +295,7 @@
   template(com_sun_cri_ci_CiRegister,                 "com/sun/cri/ci/CiRegister")                                      \
   template(com_sun_cri_ci_CiCodePos,                  "com/sun/cri/ci/CiCodePos")                                       \
   template(com_sun_cri_ci_CiConstant,                 "com/sun/cri/ci/CiConstant")                                      \
+  template(com_sun_cri_ci_CiVirtualObject,            "com/sun/cri/ci/CiVirtualObject")                                 \
   template(com_sun_cri_ci_CiKind,                     "com/sun/cri/ci/CiKind")                                          \
   template(com_sun_cri_ci_CiRuntimeCall,              "com/sun/cri/ci/CiRuntimeCall")                                   \
   template(startCompiler_name,                        "startCompiler")                                                  \
--- a/src/share/vm/graal/graalCodeInstaller.cpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.cpp	Fri Jul 01 18:24:04 2011 +0200
@@ -107,7 +107,7 @@
 }
 
 // TODO: finish this - graal doesn't provide any scope values at the moment
-static ScopeValue* get_hotspot_value(oop value, int frame_size, ScopeValue* &second) {
+static ScopeValue* get_hotspot_value(oop value, int frame_size, GrowableArray<ScopeValue*>* objects, ScopeValue* &second) {
   second = NULL;
   if (value == CiValue::IllegalValue()) {
     return new LocationValue(Location::new_stk_loc(Location::invalid, 0));
@@ -182,6 +182,45 @@
       return new ConstantLongValue(prim);
     }
     tty->print("%i", type);
+  } else if (value->is_a(CiVirtualObject::klass())) {
+    oop type = CiVirtualObject::type(value);
+    int id = CiVirtualObject::id(value);
+    ciKlass* klass = (ciKlass*) CURRENT_ENV->get_object(java_lang_Class::as_klassOop(HotSpotTypeResolved::javaMirror(type)));
+    assert(klass->is_instance_klass() || klass->is_array_klass(), "Not supported allocation.");
+
+    for (jint i = 0; i < objects->length(); i++) {
+      ObjectValue* obj = (ObjectValue*) objects->at(i);
+      if (obj->id() == id) {
+        return obj;
+      }
+    }
+
+    ObjectValue* sv = new ObjectValue(id, new ConstantOopWriteValue(klass->constant_encoding()));
+
+    arrayOop values = (arrayOop) CiVirtualObject::values(value);
+    for (jint i = 0; i < values->length(); i++) {
+      ((oop*) values->base(T_OBJECT))[i];
+    }
+
+    for (jint i = 0; i < values->length(); i++) {
+      ScopeValue* second = NULL;
+      ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], frame_size, objects, second);
+
+//      if (second != NULL) {
+//        sv->field_values()->append(second);
+//      }
+      sv->field_values()->append(value);
+    }
+
+//    uint first_ind = spobj->first_index();
+//    for (uint i = 0; i < spobj->n_fields(); i++) {
+//      Node* fld_node = sfn->in(first_ind+i);
+//      (void)FillLocArray(sv->field_values()->length(), sfn, fld_node, sv->field_values(), objs);
+//    }
+//    scval = sv;
+
+    objects->append(sv);
+    return sv;
   } else {
     value->klass()->print();
     value->print();
@@ -421,10 +460,10 @@
 
 }
 
-void CodeInstaller::record_scope(jint pc_offset, oop code_pos) {
+void CodeInstaller::record_scope(jint pc_offset, oop code_pos, GrowableArray<ScopeValue*>* objects) {
   oop caller_pos = CiCodePos::caller(code_pos);
   if (caller_pos != NULL) {
-    record_scope(pc_offset, caller_pos);
+    record_scope(pc_offset, caller_pos, objects);
   }
   oop frame = NULL;
   if (code_pos->klass()->klass_part()->name() == vmSymbols::com_sun_cri_ci_CiFrame()) {
@@ -466,7 +505,7 @@
 
     for (jint i = 0; i < values->length(); i++) {
       ScopeValue* second = NULL;
-      ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], _frame_size, second);
+      ScopeValue* value = get_hotspot_value(((oop*) values->base(T_OBJECT))[i], _frame_size, objects, second);
 
       if (i < local_count) {
         if (second != NULL) {
@@ -492,6 +531,9 @@
         assert(((oop*) values->base(T_OBJECT))[i] == CiValue::IllegalValue(), "double-slot value not followed by CiValue.IllegalValue");
       }
     }
+
+    _debug_recorder->dump_object_pool(objects);
+
     DebugToken* locals_token = _debug_recorder->create_scope_values(locals);
     DebugToken* expressions_token = _debug_recorder->create_scope_values(expressions);
     DebugToken* monitors_token = _debug_recorder->create_monitor_values(monitors);
@@ -516,7 +558,7 @@
   _debug_recorder->add_safepoint(pc_offset, create_oop_map(_frame_size, _parameter_count, debug_info));
 
   oop code_pos = CiDebugInfo::codePos(debug_info);
-  record_scope(pc_offset, code_pos);
+  record_scope(pc_offset, code_pos, new GrowableArray<ScopeValue*>());
 
   _debug_recorder->end_safepoint(pc_offset);
 }
@@ -537,7 +579,7 @@
   if (debug_info != NULL) {
     _debug_recorder->add_safepoint(next_pc_offset, create_oop_map(_frame_size, _parameter_count, debug_info));
     oop code_pos = CiDebugInfo::codePos(debug_info);
-    record_scope(next_pc_offset, code_pos);
+    record_scope(next_pc_offset, code_pos, new GrowableArray<ScopeValue*>());
   }
 
   if (runtime_call != NULL) {
--- a/src/share/vm/graal/graalCodeInstaller.hpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/graal/graalCodeInstaller.hpp	Fri Jul 01 18:24:04 2011 +0200
@@ -99,7 +99,7 @@
   void site_DataPatch(CodeBuffer& buffer, jint pc_offset, oop site);
   void site_Mark(CodeBuffer& buffer, jint pc_offset, oop site);
 
-  void record_scope(jint pc_offset, oop code_pos);
+  void record_scope(jint pc_offset, oop code_pos, GrowableArray<ScopeValue*>* objects);
 
   void process_exception_handlers();
 
--- a/src/share/vm/graal/graalCompiler.cpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp	Fri Jul 01 18:24:04 2011 +0200
@@ -144,8 +144,13 @@
 }
 
 oop GraalCompiler::get_RiField(ciField *field, ciInstanceKlass* accessor_klass, KlassHandle accessor, Bytecodes::Code byteCode, TRAPS) {
-  bool will_link = field->will_link_from_vm(accessor_klass, byteCode);
-  int offset = (field->holder()->is_loaded() && will_link) ? field->offset() : -1;
+  int offset;
+  if (byteCode != Bytecodes::_illegal) {
+    bool will_link = field->will_link_from_vm(accessor_klass, byteCode);
+    offset = (field->holder()->is_loaded() && will_link) ? field->offset() : -1;
+  } else {
+    offset = field->offset();
+  }
   Handle field_name = VmIds::toString<Handle>(field->name()->get_symbol(), CHECK_0);
   Handle field_holder = get_RiType(field->holder(), accessor, CHECK_0);
   Handle field_type = get_RiType(field->type(), accessor, CHECK_0);
--- a/src/share/vm/graal/graalJavaAccess.hpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/graal/graalJavaAccess.hpp	Fri Jul 01 18:24:04 2011 +0200
@@ -207,6 +207,11 @@
   start_class(CiStackSlot)                                                              \
     int_field(CiStackSlot, index)                                                       \
   end_class                                                                             \
+  start_class(CiVirtualObject)                                                          \
+    int_field(CiVirtualObject, id)                                                      \
+    oop_field(CiVirtualObject, type, "Lcom/sun/cri/ri/RiType;")                         \
+    oop_field(CiVirtualObject, values, "[Lcom/sun/cri/ci/CiValue;")                     \
+  end_class                                                                             \
   start_class(RiTypeProfile)                                                            \
     int_field(RiTypeProfile, count)                                                     \
     int_field(RiTypeProfile, morphism)                                                  \
--- a/src/share/vm/graal/graalVMEntries.cpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/graal/graalVMEntries.cpp	Fri Jul 01 18:24:04 2011 +0200
@@ -631,6 +631,31 @@
   return JNIHandles::make_local(THREAD, GraalCompiler::createHotSpotTypeResolved(array, name, THREAD));
 }
 
+// public RiField[] RiType_fields(HotSpotTypeResolved klass);
+JNIEXPORT jobject JNICALL Java_com_oracle_graal_runtime_VMEntries_RiType_1fields(JNIEnv *, jobject, jobject klass) {
+  TRACE_graal_3("VMEntries::RiType_fields");
+  KlassHandle klass_handle;
+  ciInstanceKlass* instance_klass;
+  objArrayHandle fieldsArray;
+  HandleMark hm;
+  {
+    VM_ENTRY_MARK;
+    klass_handle = java_lang_Class::as_klassOop(HotSpotTypeResolved::javaMirror(klass));
+    instance_klass = (ciInstanceKlass *) CURRENT_ENV->get_object(klass_handle());
+  }
+  GrowableArray<ciField*>* fields = instance_klass->non_static_fields();
+  {
+    VM_ENTRY_MARK;
+    fieldsArray = oopFactory::new_objArray(SystemDictionary::RiField_klass(), fields->length(), CHECK_NULL);
+    for (int i = 0; i < fields->length(); i++) {
+      ciField* field = fields->at(i);
+      Handle field_handle = GraalCompiler::get_RiField(field, instance_klass, klass_handle, Bytecodes::_illegal, CHECK_NULL);
+      fieldsArray->obj_at_put(i, field_handle());
+    }
+  }
+  return JNIHandles::make_local(fieldsArray());
+}
+
 // public RiType getPrimitiveArrayType(CiKind kind);
 JNIEXPORT jobject JNICALL Java_com_oracle_graal_runtime_VMEntries_getPrimitiveArrayType(JNIEnv *env, jobject, jobject kind) {
   TRACE_graal_3("VMEntries::VMEntries_getPrimitiveArrayType");
@@ -847,6 +872,7 @@
   {CC"RiType_uniqueConcreteSubtype",    CC"("RESOLVED_TYPE")"TYPE,                  FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1uniqueConcreteSubtype)},
   {CC"RiType_superType",                CC"("RESOLVED_TYPE")"TYPE,                  FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1superType)},
   {CC"RiType_arrayOf",                  CC"("RESOLVED_TYPE")"TYPE,                  FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1arrayOf)},
+  {CC"RiType_fields",                   CC"("RESOLVED_TYPE")["FIELD,                FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1fields)},
   {CC"RiType_isInitialized",            CC"("RESOLVED_TYPE")Z",                     FN_PTR(Java_com_oracle_graal_runtime_VMEntries_RiType_1isInitialized)},
   {CC"getPrimitiveArrayType",           CC"("CI_KIND")"TYPE,                        FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getPrimitiveArrayType)},
   {CC"getType",                         CC"("CLASS")"TYPE,                          FN_PTR(Java_com_oracle_graal_runtime_VMEntries_getType)},
--- a/src/share/vm/runtime/deoptimization.cpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/runtime/deoptimization.cpp	Fri Jul 01 18:24:04 2011 +0200
@@ -206,11 +206,11 @@
   assert(vf->is_compiled_frame(), "Wrong frame type");
   chunk->push(compiledVFrame::cast(vf));
 
-#ifdef COMPILER2
+//#ifdef COMPILER2
   // Reallocate the non-escaping objects and restore their fields. Then
   // relock objects if synchronization on them was eliminated.
-  if (DoEscapeAnalysis) {
-    if (EliminateAllocations) {
+//  if (DoEscapeAnalysis) {
+//    if (EliminateAllocations) {
       assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames");
       GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
 
@@ -254,8 +254,8 @@
         // Restore result.
         deoptee.set_saved_oop_result(&map, return_value());
       }
-    }
-    if (EliminateLocks) {
+//    }
+//    if (EliminateLocks) {
 #ifndef PRODUCT
       bool first = true;
 #endif
@@ -282,9 +282,9 @@
 #endif
         }
       }
-    }
-  }
-#endif // COMPILER2
+//    }
+//  }
+//#endif // COMPILER2
   // Ensure that no safepoint is taken after pointers have been stored
   // in fields of rematerialized objects.  If a safepoint occurs from here on
   // out the java state residing in the vframeArray will be missed.
@@ -709,7 +709,7 @@
 }
 
 
-#ifdef COMPILER2
+//#ifdef COMPILER2
 bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS) {
   Handle pending_exception(thread->pending_exception());
   const char* exception_file = thread->exception_file();
@@ -951,7 +951,7 @@
   }
 }
 #endif
-#endif // COMPILER2
+//#endif // COMPILER2
 
 vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk) {
 
--- a/src/share/vm/runtime/deoptimization.hpp	Fri Jul 01 18:15:05 2011 +0200
+++ b/src/share/vm/runtime/deoptimization.hpp	Fri Jul 01 18:24:04 2011 +0200
@@ -109,7 +109,7 @@
   // executing in a particular CodeBlob if UseBiasedLocking is enabled
   static void revoke_biases_of_monitors(CodeBlob* cb);
 
-#ifdef COMPILER2
+//#ifdef COMPILER2
   // Support for restoring non-escaping objects
   static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS);
   static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type);
@@ -117,7 +117,7 @@
   static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects);
   static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread);
   NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects);)
-#endif // COMPILER2
+//#endif // COMPILER2
 
   public:
   static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk);