changeset 4200:816ac0e579fb

Move printer into separate project.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Tue, 03 Jan 2012 16:44:31 +0100
parents aaac4894175c
children de9f8d8e4172
files graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalContext.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/BasicIdealGraphPrinter.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinterObserver.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/InstructionPrinter.java graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/InstructionPrinter.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/graphbuilder/BytecodeLookupSwitch.java graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/CompilerImpl.java graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/BasicIdealGraphPrinter.java graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinterObserver.java graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/Snippets.java graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphTest.java mx/projects
diffstat 19 files changed, 1774 insertions(+), 1775 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalContext.java	Tue Jan 03 16:29:28 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/GraalContext.java	Tue Jan 03 16:44:31 2012 +0100
@@ -23,7 +23,6 @@
 package com.oracle.max.graal.compiler;
 
 import com.oracle.max.criutils.*;
-import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.observer.*;
 
 /**
@@ -32,7 +31,7 @@
  */
 public class GraalContext {
 
-    public static final GraalContext EMPTY_CONTEXT = new GraalContext(true, "silent context");
+    public static final GraalContext EMPTY_CONTEXT = new GraalContext("silent context");
 
     public final ObservableContext observable = new ObservableContext();
     public final GraalTimers timers = new GraalTimers();
@@ -40,35 +39,16 @@
 
     private final String name;
 
-    private GraalContext(boolean empty, String name) {
+    public GraalContext(String name) {
         this.name = name;
-        if (!empty) {
-            reset();
-        }
-    }
-
-    public GraalContext(String name) {
-        this(false, name);
     }
 
     public boolean isObserved() {
         return observable.isObserved();
     }
 
-    public void reset() {
-        observable.clear();
-        if (GraalOptions.PrintCFGToFile) {
-            observable.addCompilationObserver(new CFGPrinterObserver());
-        }
-        if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) {
-            CompilationObserver observer;
-            if (GraalOptions.PrintIdealGraphFile) {
-                observer = new IdealGraphPrinterObserver();
-            } else {
-                observer = new IdealGraphPrinterObserver(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort);
-            }
-            observable.addCompilationObserver(observer);
-        }
+    public void addCompilationObserver(CompilationObserver observer) {
+        observable.addCompilationObserver(observer);
     }
 
     public void print() {
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/BasicIdealGraphPrinter.java	Tue Jan 03 16:29:28 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,303 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.max.graal.compiler.debug;
-
-import java.io.*;
-import java.util.*;
-import java.util.Map.Entry;
-
-/**
- * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific data structures.
- */
-public class BasicIdealGraphPrinter {
-
-    /**
-     * Edge between two nodes.
-     */
-    public static class Edge {
-        final String from;
-        final int fromIndex;
-        final String to;
-        final int toIndex;
-        final String label;
-
-        public Edge(String from, int fromIndex, String to, int toIndex, String label) {
-            assert (from != null && to != null);
-            this.from = from;
-            this.fromIndex = fromIndex;
-            this.to = to;
-            this.toIndex = toIndex;
-            this.label = label;
-        }
-
-        @Override
-        public int hashCode() {
-            int h = from.hashCode() ^ to.hashCode();
-            h = 3 * h + fromIndex;
-            h = 5 * h + toIndex;
-            if (label != null) {
-                h ^= label.hashCode();
-            }
-            return h;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (obj == this) {
-                return true;
-            }
-            if (obj instanceof Edge) {
-                Edge other = (Edge) obj;
-                return from.equals(other.from)
-                        && fromIndex == other.fromIndex
-                        && to.equals(other.to)
-                        && toIndex == other.toIndex
-                        && (label == other.label || (label != null && label.equals(other.label)));
-            }
-            return false;
-        }
-    }
-
-    private final PrintStream stream;
-
-    /**
-     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
-     */
-    public BasicIdealGraphPrinter(OutputStream stream) {
-        this.stream = new PrintStream(stream);
-    }
-
-    /**
-     * Flushes any buffered output.
-     */
-    public void flush() {
-        stream.flush();
-    }
-
-    /**
-     * Starts a new graph document.
-     */
-    public void begin() {
-        stream.println("<graphDocument>");
-    }
-
-    public void beginGroup() {
-        stream.println("<group>");
-    }
-
-    public void beginMethod(String name, String shortName, int bci) {
-        stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci);
-    }
-
-    public void beginBytecodes() {
-        stream.println("  <bytecodes>\n<![CDATA[");
-    }
-
-    public void printBytecode(int bci, String mnemonic, int[] extra) {
-        stream.print(bci);
-        stream.print(' ');
-        stream.print(mnemonic);
-        if (extra != null) {
-            for (int b : extra) {
-                stream.print(' ');
-                stream.print(b);
-            }
-        }
-        stream.println();
-    }
-
-    public void endBytecodes() {
-        stream.println("  ]]></bytecodes>");
-    }
-
-    public void endMethod() {
-        stream.println(" </method>");
-    }
-
-    public void beginGraph(String title) {
-        stream.printf(" <graph name='%s'>%n", escape(title));
-    }
-
-    public void beginProperties() {
-        stream.print("<properties>");
-    }
-
-    public void printProperty(String name, String value) {
-        stream.printf("<p name='%s'>%s</p>", escape(name), escape(value));
-    }
-
-    public void endProperties() {
-        stream.print("</properties>");
-    }
-
-    public void printProperties(Map<String, String> properties) {
-        beginProperties();
-        for (Entry<String, String> entry : properties.entrySet()) {
-            printProperty(entry.getKey(), entry.getValue());
-        }
-        endProperties();
-    }
-
-    public void beginNodes() {
-        stream.println("  <nodes>");
-    }
-
-    public void beginNode(String id) {
-        stream.printf("   <node id='%s'>", escape(id));
-    }
-
-    public void endNode() {
-        stream.println("   </node>");
-    }
-
-    public void printNode(String id, Map<String, String> properties) {
-        beginNode(id);
-        if (properties != null) {
-            printProperties(properties);
-        }
-        endNode();
-    }
-
-    public void endNodes() {
-        stream.println("  </nodes>");
-    }
-
-    public void beginEdges() {
-        stream.println("  <edges>");
-    }
-
-    public void printEdge(Edge edge) {
-        stream.printf("   <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label));
-    }
-
-    public void endEdges() {
-        stream.println("  </edges>");
-    }
-
-    public void beginControlFlow() {
-        stream.println("  <controlFlow>");
-    }
-
-    public void beginBlock(String name) {
-        stream.printf("   <block name='%s'>%n", escape(name));
-    }
-
-    public void beginSuccessors() {
-        stream.println("    <successors>");
-    }
-
-    public void printSuccessor(String name) {
-        stream.printf("     <successor name='%s'/>%n", escape(name));
-    }
-
-    public void endSuccessors() {
-        stream.println("    </successors>");
-    }
-
-    public void beginBlockNodes() {
-        stream.println("    <nodes>");
-    }
-
-    public void printBlockNode(String nodeId) {
-        stream.printf("     <node id='%s'/>%n", escape(nodeId));
-    }
-
-    public void endBlockNodes() {
-        stream.println("    </nodes>");
-    }
-
-    public void endBlock() {
-        stream.println("   </block>");
-    }
-
-    public void endControlFlow() {
-        stream.println("  </controlFlow>");
-    }
-
-    public void endGraph() {
-        stream.println(" </graph>");
-    }
-
-    /**
-     * Ends the current group.
-     */
-    public void endGroup() {
-        stream.println("</group>");
-    }
-
-    /**
-     * Finishes the graph document and flushes the output stream.
-     */
-    public void end() {
-        stream.println("</graphDocument>");
-        flush();
-    }
-
-    private static String escape(String s) {
-        StringBuilder str = null;
-        for (int i = 0; i < s.length(); i++) {
-            char c = s.charAt(i);
-            switch (c) {
-                case '&':
-                case '<':
-                case '>':
-                case '"':
-                case '\'':
-                    if (str == null) {
-                        str = new StringBuilder();
-                        str.append(s, 0, i);
-                    }
-                    switch(c) {
-                        case '&':
-                            str.append("&amp;");
-                            break;
-                        case '<':
-                            str.append("&lt;");
-                            break;
-                        case '>':
-                            str.append("&gt;");
-                            break;
-                        case '"':
-                            str.append("&quot;");
-                            break;
-                        case '\'':
-                            str.append("&apos;");
-                            break;
-                        default:
-                            assert false;
-                    }
-                    break;
-                default:
-                    if (str != null) {
-                        str.append(c);
-                    }
-                    break;
-            }
-        }
-        if (str == null) {
-            return s;
-        } else {
-            return str.toString();
-        }
-    }
-}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinter.java	Tue Jan 03 16:29:28 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,480 +0,0 @@
-/*
- * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.max.graal.compiler.debug;
-
-import static com.oracle.max.cri.ci.CiValueUtil.*;
-
-import java.io.*;
-import java.util.*;
-
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.criutils.*;
-import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.alloc.*;
-import com.oracle.max.graal.compiler.alloc.Interval.UsePosList;
-import com.oracle.max.graal.compiler.graphbuilder.*;
-import com.oracle.max.graal.compiler.lir.*;
-import com.oracle.max.graal.compiler.schedule.*;
-import com.oracle.max.graal.graph.*;
-import com.oracle.max.graal.graph.Node.*;
-import com.oracle.max.graal.graph.NodeClass.*;
-import com.oracle.max.graal.nodes.*;
-import com.oracle.max.graal.nodes.calc.*;
-
-/**
- * Utility for printing Graal IR at various compilation phases.
- */
-public class CFGPrinter extends CompilationPrinter {
-
-    public final ByteArrayOutputStream buffer;
-    public final GraalCompilation compilation;
-    public final CiTarget target;
-    public final RiRuntime runtime;
-
-    /**
-     * Creates a control flow graph printer.
-     *
-     * @param buffer where the output generated via this printer shown be written
-     */
-    public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation) {
-        super(buffer);
-        this.buffer = buffer;
-        this.compilation = compilation;
-        this.target = compilation.compiler.target;
-        this.runtime = compilation.compiler.runtime;
-    }
-
-    public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation, CiTarget target, RiRuntime runtime) {
-        super(buffer);
-        this.buffer = buffer;
-        this.compilation = compilation;
-        this.target = target;
-        this.runtime = runtime;
-    }
-
-    /**
-     * Prints the control flow graph denoted by a given block map.
-     *
-     * @param label A label describing the compilation phase that produced the control flow graph.
-     * @param blockMap A data structure describing the blocks in a method and how they are connected.
-     */
-    public void printCFG(String label, BlockMap blockMap) {
-        begin("cfg");
-        out.print("name \"").print(label).println('"');
-        for (BlockMap.Block block : blockMap.blocks) {
-            begin("block");
-            printBlock(block);
-            end("block");
-        }
-        end("cfg");
-    }
-
-    private void printBlock(BlockMap.Block block) {
-        out.print("name \"B").print(block.startBci).println('"');
-        out.print("from_bci ").println(block.startBci);
-        out.print("to_bci ").println(block.endBci);
-
-        out.println("predecessors ");
-
-        out.print("successors ");
-        for (BlockMap.Block succ : block.successors) {
-            if (!succ.isExceptionEntry) {
-                out.print("\"B").print(succ.startBci).print("\" ");
-            }
-        }
-        out.println();
-
-        out.print("xhandlers");
-        for (BlockMap.Block succ : block.successors) {
-            if (succ.isExceptionEntry) {
-                out.print("\"B").print(succ.startBci).print("\" ");
-            }
-        }
-        out.println();
-
-        out.print("flags ");
-        if (block.isExceptionEntry) {
-            out.print("\"ex\" ");
-        }
-        if (block.isLoopHeader) {
-            out.print("\"plh\" ");
-        }
-        out.println();
-
-        out.print("loop_depth ").println(Long.bitCount(block.loops));
-    }
-
-
-    /**
-     * Prints the specified list of blocks.
-     *
-     * @param label A label describing the compilation phase that produced the control flow graph.
-     * @param blocks The list of blocks to be printed.
-     * @param printNodes If {@code true} the nodes in the block will be printed.
-     */
-    public void printCFG(String label, List<? extends Block> blocks, boolean printNodes) {
-        begin("cfg");
-        out.print("name \"").print(label).println('"');
-        for (Block block : blocks) {
-            printBlock(block, printNodes);
-        }
-        end("cfg");
-    }
-
-    private void printBlock(Block block, boolean printNodes) {
-        begin("block");
-
-        out.print("name \"").print(blockToString(block)).println('"');
-        out.println("from_bci -1");
-        out.println("to_bci -1");
-
-        out.print("predecessors ");
-        for (Block pred : block.getPredecessors()) {
-            out.print("\"").print(blockToString(pred)).print("\" ");
-        }
-        out.println();
-
-        out.print("successors ");
-        for (Block succ : block.getSuccessors()) {
-            if (!succ.isExceptionBlock()) {
-                out.print("\"").print(blockToString(succ)).print("\" ");
-            }
-        }
-        out.println();
-
-        out.print("xhandlers");
-        for (Block succ : block.getSuccessors()) {
-            if (succ.isExceptionBlock()) {
-                out.print("\"").print(blockToString(succ)).print("\" ");
-            }
-        }
-        out.println();
-
-        out.print("flags ");
-        if (block.isLoopHeader()) {
-            out.print("\"llh\" ");
-        }
-        if (block.isLoopEnd()) {
-            out.print("\"lle\" ");
-        }
-        if (block.isExceptionBlock()) {
-            out.print("\"ex\" ");
-        }
-        out.println();
-
-        out.print("loop_index ").println(block.loopIndex());
-        out.print("loop_depth ").println(block.loopDepth());
-
-        if (printNodes) {
-            printNodes(block);
-        }
-
-        if (block instanceof LIRBlock) {
-            printLIR((LIRBlock) block);
-        }
-
-        end("block");
-    }
-
-    private void printNodes(Block block) {
-        begin("IR");
-        out.println("HIR");
-        out.disableIndentation();
-
-        if (block.getPredecessors().size() == 0) {
-            // Currently method parameters are not in the schedule, so print them separately here.
-            for (ValueNode param : block.firstNode().graph().getNodes(LocalNode.class)) {
-                printNode(param);
-            }
-        }
-        if (block.firstNode() instanceof MergeNode) {
-            // Currently phi functions are not in the schedule, so print them separately here.
-            for (ValueNode phi : ((MergeNode) block.firstNode()).phis()) {
-                printNode(phi);
-            }
-        }
-
-        for (Node node : block.getInstructions()) {
-            printNode(node);
-        }
-        out.enableIndentation();
-        end("IR");
-    }
-
-    private void printNode(Node node) {
-        if (node instanceof FixedWithNextNode) {
-            out.print("f ").print(HOVER_START).print("#").print(HOVER_SEP).print("fixed with next").print(HOVER_END).println(COLUMN_END);
-        } else if (node instanceof FixedNode) {
-            out.print("f ").print(HOVER_START).print("*").print(HOVER_SEP).print("fixed").print(HOVER_END).println(COLUMN_END);
-        } else if (node instanceof FloatingNode) {
-            out.print("f ").print(HOVER_START).print("~").print(HOVER_SEP).print("floating").print(HOVER_END).println(COLUMN_END);
-        }
-        if (compilation.nodeOperands != null && node instanceof ValueNode) {
-            CiValue operand = compilation.operand((ValueNode) node);
-            if (operand != null) {
-                out.print("result ").print(operand.toString()).println(COLUMN_END);
-            }
-        }
-        out.print("tid ").print(nodeToString(node)).println(COLUMN_END);
-
-        if (node instanceof StateSplit) {
-            StateSplit stateSplit = (StateSplit) node;
-            if (stateSplit.stateAfter() != null) {
-                String state = stateToString(stateSplit.stateAfter());
-                out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END);
-            }
-        }
-
-        Map<Object, Object> props = new TreeMap<>(node.getDebugProperties());
-        out.print("d ").print(HOVER_START).print("d").print(HOVER_SEP);
-        out.println("=== Debug Properties ===");
-        for (Map.Entry<Object, Object> entry : props.entrySet()) {
-            out.print(entry.getKey().toString()).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).println();
-        }
-        out.println("=== Inputs ===");
-        printNamedNodes(node, node.inputs().iterator(), "", "\n", null);
-        out.println("=== Succesors ===");
-        printNamedNodes(node, node.successors().iterator(), "", "\n", null);
-        out.println("=== Usages ===");
-        if (!node.usages().isEmpty()) {
-            for (Node usage : node.usages()) {
-                out.print(nodeToString(usage)).print(" ");
-            }
-            out.println();
-        }
-        out.println("=== Predecessor ===");
-        out.print(nodeToString(node.predecessor())).print(" ");
-        out.print(HOVER_END).println(COLUMN_END);
-
-        out.print("instruction ");
-        out.print(HOVER_START).print(node.getNodeClass().shortName()).print(HOVER_SEP).print(node.getClass().getName()).print(HOVER_END).print(" ");
-        printNamedNodes(node, node.inputs().iterator(), "", "", "#NDF");
-        printNamedNodes(node, node.successors().iterator(), "#", "", "#NDF");
-        for (Map.Entry<Object, Object> entry : props.entrySet()) {
-            String key = entry.getKey().toString();
-            if (key.startsWith("data.") && !key.equals("data.stamp")) {
-                out.print(key.substring("data.".length())).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).print(" ");
-            }
-        }
-        out.print(COLUMN_END).print(' ').println(COLUMN_END);
-    }
-
-    private void printNamedNodes(Node node, NodeClassIterator iter, String prefix, String suffix, String hideSuffix) {
-        int lastIndex = -1;
-        while (iter.hasNext()) {
-            Position pos = iter.nextPosition();
-            if (hideSuffix != null && node.getNodeClass().getName(pos).endsWith(hideSuffix)) {
-                continue;
-            }
-
-            if (pos.index != lastIndex) {
-                if (lastIndex != -1) {
-                    out.print(suffix);
-                }
-                out.print(prefix).print(node.getNodeClass().getName(pos)).print(": ");
-                lastIndex = pos.index;
-            }
-            out.print(nodeToString(node.getNodeClass().get(node, pos))).print(" ");
-        }
-        if (lastIndex != -1) {
-            out.print(suffix);
-        }
-    }
-
-    private String stateToString(FrameState state) {
-        StringBuilder buf = new StringBuilder();
-        FrameState curState = state;
-        do {
-            buf.append(CiUtil.toLocation(curState.method(), curState.bci)).append('\n');
-
-            if (curState.stackSize() > 0) {
-                buf.append("stack: ");
-                for (int i = 0; i < curState.stackSize(); i++) {
-                    buf.append(stateValueToString(curState.stackAt(i))).append(' ');
-                }
-                buf.append("\n");
-            }
-
-            if (curState.locksSize() > 0) {
-                buf.append("locks: ");
-                for (int i = 0; i < curState.locksSize(); ++i) {
-                    buf.append(stateValueToString(curState.lockAt(i))).append(' ');
-                }
-                buf.append("\n");
-            }
-
-            buf.append("locals: ");
-            for (int i = 0; i < curState.localsSize(); i++) {
-                buf.append(stateValueToString(curState.localAt(i))).append(' ');
-            }
-            buf.append("\n");
-
-            curState = curState.outerFrameState();
-        } while (curState != null);
-
-        return buf.toString();
-    }
-
-    private String stateValueToString(ValueNode value) {
-        String result = nodeToString(value);
-        if (value != null) {
-            CiValue operand = compilation.operand(value);
-            if (operand != null) {
-                result += ": " + operand;
-            }
-        }
-        return result;
-    }
-
-    /**
-     * Prints the LIR for each instruction in a given block.
-     *
-     * @param block the block to print
-     */
-    private void printLIR(LIRBlock block) {
-        List<LIRInstruction> lir = block.lir();
-        if (lir == null) {
-            return;
-        }
-
-        begin("IR");
-        out.println("LIR");
-
-        if (block.phis != null) {
-            CiValue[] results = block.phis.results();
-            for (int i = 0; i < results.length; i++) {
-                out.print("instruction PHI ").print(results[i].toString()).print(" = (");
-                String sep = "";
-                for (LIRBlock pred : block.getLIRPredecessors()) {
-                    out.print(sep).print(block.phis.inputs(pred)[i].toString());
-                    sep = ", ";
-                }
-                out.print(")").print(COLUMN_END).println(COLUMN_END);
-            }
-        }
-
-        for (int i = 0; i < lir.size(); i++) {
-            LIRInstruction inst = lir.get(i);
-            out.printf("nr %4d ", inst.id()).print(COLUMN_END);
-
-            if (inst.info != null) {
-                int level = out.indentationLevel();
-                out.adjustIndentation(-level);
-                String state;
-                if (inst.info.hasDebugInfo()) {
-                    state = debugInfoToString(inst.info.debugInfo().codePos, inst.info.debugInfo().registerRefMap, inst.info.debugInfo().frameRefMap, target.arch);
-                } else {
-                    state = debugInfoToString(inst.info.topFrame, null, null, target.arch);
-                }
-                if (state != null) {
-                    out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END);
-                }
-                out.adjustIndentation(level);
-            }
-
-            out.print(" instruction ").print(inst.toString()).print(COLUMN_END);
-            out.println(COLUMN_END);
-        }
-        end("IR");
-    }
-
-    private String nodeToString(Node node) {
-        if (node == null) {
-            return "-";
-        }
-        String prefix;
-        if (node instanceof BeginNode && compilation != null && compilation.lir() == null) {
-            prefix = "B";
-        } else if (node instanceof ValueNode) {
-            ValueNode value = (ValueNode) node;
-            if (value.kind() == CiKind.Illegal) {
-                prefix = "v";
-            } else {
-                prefix = String.valueOf(value.kind().typeChar);
-            }
-        } else {
-            prefix = "?";
-        }
-        return prefix + node.toString(Verbosity.Id);
-    }
-
-    private String blockToString(Block block) {
-        if (compilation != null && compilation.lir() == null) {
-            // During all the front-end phases, the block schedule is built only for the debug output.
-            // Therefore, the block numbers would be different for every CFG printed -> use the id of the first instruction.
-            return "B" + block.firstNode().toString(Verbosity.Id);
-        } else {
-            // LIR instructions contain references to blocks and these blocks are printed as the blockID -> use the blockID.
-            return "B" + block.blockID();
-        }
-    }
-
-
-    public void printIntervals(String label, Interval[] intervals) {
-        begin("intervals");
-        out.println(String.format("name \"%s\"", label));
-
-        for (Interval interval : intervals) {
-            if (interval != null) {
-                printInterval(interval);
-            }
-        }
-
-        end("intervals");
-    }
-
-    private void printInterval(Interval interval) {
-        out.printf("%s %s ", interval.operand, (isRegister(interval.operand) ? "fixed" : interval.kind().name()));
-        if (isRegister(interval.operand)) {
-            out.printf("\"[%s|%c]\"", interval.operand, interval.operand.kind.typeChar);
-        } else {
-            if (interval.location() != null) {
-                out.printf("\"[%s|%c]\"", interval.location(), interval.location().kind.typeChar);
-            }
-        }
-
-        Interval hint = interval.locationHint(false);
-        out.printf("%s %s ", interval.splitParent().operand, hint != null ? hint.operand : -1);
-
-        // print ranges
-        Range cur = interval.first();
-        while (cur != Range.EndMarker) {
-            out.printf("[%d, %d[", cur.from, cur.to);
-            cur = cur.next;
-            assert cur != null : "range list not closed with range sentinel";
-        }
-
-        // print use positions
-        int prev = 0;
-        UsePosList usePosList = interval.usePosList();
-        for (int i = usePosList.size() - 1; i >= 0; --i) {
-            assert prev < usePosList.usePos(i) : "use positions not sorted";
-            out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i));
-            prev = usePosList.usePos(i);
-        }
-
-        out.printf(" \"%s\"", interval.spillState());
-        out.println();
-    }
-}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/CFGPrinterObserver.java	Tue Jan 03 16:29:28 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,138 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.max.graal.compiler.debug;
-
-import java.io.*;
-import java.util.*;
-
-import com.oracle.max.cri.ci.*;
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.criutils.*;
-import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.alloc.*;
-import com.oracle.max.graal.compiler.graphbuilder.*;
-import com.oracle.max.graal.compiler.lir.*;
-import com.oracle.max.graal.compiler.observer.*;
-import com.oracle.max.graal.compiler.schedule.*;
-import com.oracle.max.graal.graph.*;
-import com.oracle.max.graal.nodes.*;
-
-/**
- * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the <a
- * href="http://java.net/projects/c1visualizer/">C1 Visualizer</a>.
- */
-public class CFGPrinterObserver implements CompilationObserver {
-
-    /**
-     * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation.
-     */
-    private ThreadLocal<LinkedList<CFGPrinter>> observations = new ThreadLocal<LinkedList<CFGPrinter>>() {
-        @Override
-        protected java.util.LinkedList<CFGPrinter> initialValue() {
-            return new LinkedList<>();
-        }
-    };
-
-    @Override
-    public void compilationStarted(GraalCompilation compilation) {
-        if (TTY.isSuppressed()) {
-            return;
-        }
-
-        CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), compilation);
-        cfgPrinter.printCompilation(compilation.method);
-        observations.get().push(cfgPrinter);
-    }
-
-    @Override
-    public void compilationEvent(CompilationEvent event) {
-        if (TTY.isSuppressed()) {
-            return;
-        }
-        CFGPrinter cfgPrinter = observations.get().peek();
-        if (cfgPrinter == null) {
-            return;
-        }
-
-        RiRuntime runtime = cfgPrinter.runtime;
-        BlockMap blockMap = event.debugObject(BlockMap.class);
-        Graph graph = event.debugObject(Graph.class);
-        IdentifyBlocksPhase schedule = event.debugObject(IdentifyBlocksPhase.class);
-        LIR lir = event.debugObject(LIR.class);
-        LinearScan allocator = event.debugObject(LinearScan.class);
-        Interval[] intervals = event.debugObject(Interval[].class);
-        CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class);
-
-        if (blockMap != null) {
-            cfgPrinter.printCFG(event.label, blockMap);
-            cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method));
-        }
-        if (lir != null) {
-            cfgPrinter.printCFG(event.label, lir.codeEmittingOrder(), graph != null);
-            if (targetMethod != null) {
-                cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null);
-            }
-        } else if (graph != null) {
-            List<? extends Block> blocks = null;
-            if (schedule == null) {
-                try {
-                    schedule = new IdentifyBlocksPhase(true, LIRBlock.FACTORY);
-                    schedule.apply((StructuredGraph) graph, false);
-                    blocks = schedule.getBlocks();
-
-                    ComputeLinearScanOrder clso = new ComputeLinearScanOrder(schedule.getBlocks().size(), schedule.loopCount(), (LIRBlock) schedule.getStartBlock());
-                    blocks = clso.codeEmittingOrder();
-                } catch (Throwable t) {
-                    // nothing to do here...
-                }
-            }
-            if (blocks != null) {
-                cfgPrinter.printCFG(event.label, blocks, true);
-            }
-        }
-        if (allocator != null && intervals != null) {
-            cfgPrinter.printIntervals(event.label, intervals);
-        }
-    }
-
-    @Override
-    public void compilationFinished(GraalCompilation compilation) {
-        if (TTY.isSuppressed()) {
-            return;
-        }
-        CFGPrinter cfgPrinter = observations.get().pop();
-        cfgPrinter.flush();
-
-        OutputStream stream = CompilationPrinter.globalOut();
-        if (stream != null) {
-            synchronized (stream) {
-                try {
-                    stream.write(cfgPrinter.buffer.toByteArray());
-                    stream.flush();
-                } catch (IOException e) {
-                    TTY.println("WARNING: Error writing CFGPrinter output: %s", e);
-                }
-            }
-        }
-    }
-}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinter.java	Tue Jan 03 16:29:28 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,419 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.max.graal.compiler.debug;
-
-import java.io.*;
-import java.util.*;
-import java.util.Map.Entry;
-
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.debug.BasicIdealGraphPrinter.Edge;
-import com.oracle.max.graal.compiler.graphbuilder.*;
-import com.oracle.max.graal.compiler.schedule.*;
-import com.oracle.max.graal.compiler.util.*;
-import com.oracle.max.graal.compiler.util.LoopUtil.Loop;
-import com.oracle.max.graal.graph.*;
-import com.oracle.max.graal.graph.Node.Verbosity;
-import com.oracle.max.graal.graph.NodeClass.NodeClassIterator;
-import com.oracle.max.graal.graph.NodeClass.Position;
-import com.oracle.max.graal.nodes.*;
-import com.oracle.max.graal.nodes.loop.*;
-
-/**
- * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the <a
- * href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
- */
-public class IdealGraphPrinter {
-
-    private final BasicIdealGraphPrinter printer;
-    private final HashSet<Class<?>> omittedClasses = new HashSet<>();
-    private final Set<Node> noBlockNodes = new HashSet<>();
-
-    /**
-     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
-     */
-    public IdealGraphPrinter(OutputStream stream) {
-        this.printer = new BasicIdealGraphPrinter(stream);
-    }
-
-    /**
-     * Adds a node class that is omitted in the output.
-     */
-    public void addOmittedClass(Class<?> clazz) {
-        omittedClasses.add(clazz);
-    }
-
-    /**
-     * Flushes any buffered output.
-     */
-    public void flush() {
-        printer.flush();
-    }
-
-    /**
-     * Starts a new graph document.
-     */
-    public void begin() {
-        printer.begin();
-    }
-
-    /**
-     * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties.
-     */
-    public void beginGroup(String name, String shortName, RiResolvedMethod method, int bci, String origin) {
-        printer.beginGroup();
-        printer.beginProperties();
-        printer.printProperty("name", name);
-        printer.printProperty("origin", origin);
-        printer.endProperties();
-        printer.beginMethod(name, shortName, bci);
-        if (GraalOptions.PrintIdealGraphBytecodes && method != null) {
-            printer.beginBytecodes();
-            BytecodeStream bytecodes = new BytecodeStream(method.code());
-            while (bytecodes.currentBC() != Bytecodes.END) {
-                int startBCI = bytecodes.currentBCI();
-                String mnemonic = Bytecodes.nameOf(bytecodes.currentBC());
-                int[] extra = null;
-                if (bytecodes.nextBCI() > startBCI + 1) {
-                    extra = new int[bytecodes.nextBCI() - (startBCI + 1)];
-                    for (int i = 0; i < extra.length; i++) {
-                        extra[i] = bytecodes.readUByte(startBCI + 1 + i);
-                    }
-                }
-                printer.printBytecode(startBCI, mnemonic, extra);
-                bytecodes.next();
-            }
-            printer.endBytecodes();
-        }
-        printer.endMethod();
-    }
-
-    /**
-     * Ends the current group.
-     */
-    public void endGroup() {
-        printer.endGroup();
-    }
-
-    /**
-     * Finishes the graph document and flushes the output stream.
-     */
-    public void end() {
-        printer.end();
-    }
-
-    public void print(Graph graph, String title, boolean shortNames) {
-        print(graph, title, shortNames, null);
-    }
-
-    /**
-     * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes.
-     */
-    public void print(Graph graph, String title, boolean shortNames, IdentifyBlocksPhase predefinedSchedule) {
-        printer.beginGraph(title);
-        noBlockNodes.clear();
-        IdentifyBlocksPhase schedule = predefinedSchedule;
-        if (schedule == null) {
-            try {
-                schedule = new IdentifyBlocksPhase(true);
-                schedule.apply((StructuredGraph) graph, false);
-            } catch (Throwable t) {
-                // nothing to do here...
-            }
-        }
-        List<Loop> loops = null;
-        try {
-            loops = LoopUtil.computeLoops((StructuredGraph) graph);
-            // loop.nodes() does some more calculations which may fail, so execute this here as well (result is cached)
-            if (loops != null) {
-                for (Loop loop : loops) {
-                    loop.nodes();
-                }
-            }
-        } catch (Throwable t) {
-            t.printStackTrace();
-            loops = null;
-        }
-
-        printer.beginNodes();
-        List<Edge> edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops);
-        printer.endNodes();
-
-        printer.beginEdges();
-        for (Edge edge : edges) {
-            printer.printEdge(edge);
-        }
-        printer.endEdges();
-
-        if (schedule != null) {
-            printer.beginControlFlow();
-            for (Block block : schedule.getBlocks()) {
-                printBlock(graph, block, schedule.getNodeToBlock());
-            }
-            printNoBlock();
-            printer.endControlFlow();
-        }
-
-        printer.endGraph();
-        flush();
-    }
-
-    private List<Edge> printNodes(Graph graph, boolean shortNames, NodeMap<Block> nodeToBlock, List<Loop> loops) {
-        ArrayList<Edge> edges = new ArrayList<>();
-        NodeBitMap loopExits = graph.createNodeBitMap();
-        if (loops != null) {
-            for (Loop loop : loops) {
-                loopExits.setUnion(loop.exits());
-            }
-        }
-
-        NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap();
-        NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap();
-        NodeMap<Set<String>> bits = graph.createNodeMap();
-// TODO This code was never reachable, since there was no code putting a NodeMap or NodeBitMap into the debugObjects.
-// If you need to reactivate this code, put the mapping from names to values into a helper object and register it in the new debugObjects array.
-//
-//        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));
-//                        Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node);
-//                        if (nodeColorStrings == null) {
-//                            nodeColorStrings = new HashSet<Entry<String, String>>();
-//                            colorsToString.put(node, nodeColorStrings);
-//                        }
-//                        nodeColorStrings.add(new SimpleImmutableEntry<String, String>(name, color.toString()));
-//                    }
-//                } 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()) {
-            if (omittedClasses.contains(node.getClass())) {
-                continue;
-            }
-
-            printer.beginNode(node.toString(Verbosity.Id));
-            printer.beginProperties();
-            printer.printProperty("idx", node.toString(Verbosity.Id));
-
-            Map<Object, Object> props = node.getDebugProperties();
-            if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) {
-                String name;
-                if (shortNames) {
-                    name = node.toString(Verbosity.Name);
-                } else {
-                    name = node.toString();
-                }
-                printer.printProperty("name", name);
-            }
-            printer.printProperty("class", node.getClass().getSimpleName());
-            Block block = nodeToBlock == null ? null : nodeToBlock.get(node);
-            if (block != null) {
-                printer.printProperty("block", Integer.toString(block.blockID()));
-                if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof LocalNode || node instanceof InductionVariableNode) && !block.getInstructions().contains(node)) {
-                    printer.printProperty("notInOwnBlock", "true");
-                }
-            } else {
-                printer.printProperty("block", "noBlock");
-                noBlockNodes.add(node);
-            }
-            if (loopExits.isMarked(node)) {
-                printer.printProperty("loopExit", "true");
-            }
-            StringBuilder sb = new StringBuilder();
-            if (loops != null) {
-                for (Loop loop : loops) {
-                    if (loop.nodes().isMarked(node)) {
-                        if (sb.length() > 0) {
-                            sb.append(", ");
-                        }
-                        sb.append(loop.loopBegin().toString(Verbosity.Id));
-                    }
-                }
-            }
-            if (sb.length() > 0) {
-                printer.printProperty("loops", sb.toString());
-            }
-
-            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();
-                    printer.printProperty(name, Integer.toString(value));
-                }
-            }
-            Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node);
-            if (nodeColorStrings != null) {
-                for (Entry<String, String> color : nodeColorStrings) {
-                    String name = color.getKey();
-                    String value = color.getValue();
-                    printer.printProperty(name, value);
-                }
-            }
-            Set<String> nodeBits = bits.get(node);
-            if (nodeBits != null) {
-                for (String bit : nodeBits) {
-                    printer.printProperty(bit, "true");
-                }
-            }
-
-            for (Entry<Object, Object> entry : props.entrySet()) {
-                String key = entry.getKey().toString();
-                String value = entry.getValue() == null ? "null" : entry.getValue().toString();
-                printer.printProperty(key, value);
-            }
-
-            printer.endProperties();
-            printer.endNode();
-
-            // successors
-            int fromIndex = 0;
-            NodeClassIterator succIter = node.successors().iterator();
-            while (succIter.hasNext()) {
-                Position position = succIter.nextPosition();
-                Node successor = node.getNodeClass().get(node, position);
-                if (successor != null && !omittedClasses.contains(successor.getClass())) {
-                    edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, node.getNodeClass().getName(position)));
-                }
-                fromIndex++;
-            }
-
-            // inputs
-            int toIndex = 1;
-            NodeClassIterator inputIter = node.inputs().iterator();
-            while (inputIter.hasNext()) {
-                Position position = inputIter.nextPosition();
-                Node input = node.getNodeClass().get(node, position);
-                if (input != null && !omittedClasses.contains(input.getClass())) {
-                    edges.add(new Edge(input.toString(Verbosity.Id), input.successors().explicitCount(), node.toString(Verbosity.Id), toIndex, node.getNodeClass().getName(position)));
-                }
-                toIndex++;
-            }
-        }
-
-        return edges;
-    }
-
-    private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) {
-        printer.beginBlock(Integer.toString(block.blockID()));
-        printer.beginSuccessors();
-        for (Block sux : block.getSuccessors()) {
-            if (sux != null) {
-                printer.printSuccessor(Integer.toString(sux.blockID()));
-            }
-        }
-        printer.endSuccessors();
-        printer.beginBlockNodes();
-
-        Set<Node> nodes = new HashSet<>(block.getInstructions());
-
-        if (nodeToBlock != null) {
-            for (Node n : graph.getNodes()) {
-                Block blk = nodeToBlock.get(n);
-                if (blk == block) {
-                    nodes.add(n);
-                }
-            }
-        }
-
-        if (nodes.size() > 0) {
-            // if this is the first block: add all locals to this block
-            if (block.getInstructions().size() > 0 && block.getInstructions().get(0) == ((StructuredGraph) graph).start()) {
-                for (Node node : graph.getNodes()) {
-                    if (node instanceof LocalNode) {
-                        nodes.add(node);
-                    }
-                }
-            }
-
-            // add all framestates and phis to their blocks
-            for (Node node : block.getInstructions()) {
-                if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {
-                    nodes.add(((StateSplit) node).stateAfter());
-                }
-                if (node instanceof MergeNode) {
-                    for (PhiNode phi : ((MergeNode) node).phis()) {
-                        nodes.add(phi);
-                    }
-                    if (node instanceof LoopBeginNode) {
-                        for (InductionVariableNode iv : ((LoopBeginNode) node).inductionVariables()) {
-                            nodes.add(iv);
-                        }
-                    }
-                }
-            }
-
-            for (Node node : nodes) {
-                if (!omittedClasses.contains(node.getClass())) {
-                    printer.printBlockNode(node.toString(Verbosity.Id));
-                }
-            }
-        }
-        printer.endBlockNodes();
-        printer.endBlock();
-    }
-
-    private void printNoBlock() {
-        if (!noBlockNodes.isEmpty()) {
-            printer.beginBlock("noBlock");
-            printer.beginBlockNodes();
-            for (Node node : noBlockNodes) {
-                printer.printBlockNode(node.toString(Verbosity.Id));
-            }
-            printer.endBlockNodes();
-            printer.endBlock();
-        }
-    }
-
-}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/IdealGraphPrinterObserver.java	Tue Jan 03 16:29:28 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.max.graal.compiler.debug;
-
-import java.io.*;
-import java.net.*;
-import java.util.regex.*;
-
-import com.oracle.max.cri.ri.*;
-import com.oracle.max.criutils.*;
-import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.observer.*;
-import com.oracle.max.graal.compiler.schedule.*;
-import com.oracle.max.graal.graph.*;
-
-/**
- * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be
- * inspected with the <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
- */
-public class IdealGraphPrinterObserver implements CompilationObserver {
-
-    private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]");
-
-    private final String host;
-    private final int port;
-
-    private static class PrintingContext {
-        public IdealGraphPrinter printer;
-        private OutputStream stream;
-        private Socket socket;
-
-    }
-    private final ThreadLocal<PrintingContext> context = new ThreadLocal<PrintingContext>() {
-        @Override
-        protected PrintingContext initialValue() {
-            return new PrintingContext();
-        }
-    };
-
-    /**
-     * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method.
-     */
-    public IdealGraphPrinterObserver() {
-        this(null, -1);
-    }
-
-    /**
-     * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remote IdealGraphVisualizer instance.
-     */
-    public IdealGraphPrinterObserver(String host, int port) {
-        this.host = host;
-        this.port = port;
-    }
-
-    private PrintingContext context() {
-        return context.get();
-    }
-
-    private IdealGraphPrinter printer() {
-        return context().printer;
-    }
-
-    private Socket socket() {
-        return context().socket;
-    }
-
-    @Override
-    public void compilationStarted(GraalCompilation compilation) {
-        openPrinter(compilation, false);
-    }
-
-    private void openPrinter(GraalCompilation compilation, boolean error) {
-        assert (context().stream == null && printer() == null);
-        if ((!TTY.isSuppressed() && GraalOptions.Plot) || (GraalOptions.PlotOnError && error)) {
-            String name;
-            if (compilation != null) {
-                name = compilation.method.holder().name();
-                name = name.substring(1, name.length() - 1).replace('/', '.');
-                name = name + "." + compilation.method.name();
-            } else {
-                name = "null";
-            }
-
-            openPrinter(name, compilation == null ? null : compilation.method);
-        }
-    }
-
-    private void openPrinter(String title, RiResolvedMethod method) {
-        assert (context().stream == null && printer() == null);
-        if (!TTY.isSuppressed()) {
-            // Use a filter to suppress a recursive attempt to open a printer
-            TTY.Filter filter = new TTY.Filter();
-            try {
-                if (host != null) {
-                    openNetworkPrinter(title, method);
-                } else {
-                    openFilePrinter(title, method);
-                }
-            } finally {
-                filter.remove();
-            }
-        }
-    }
-
-    private void openFilePrinter(String title, RiResolvedMethod method) {
-        String filename = title + ".igv.xml";
-        filename = INVALID_CHAR.matcher(filename).replaceAll("_");
-
-        try {
-            context().stream = new FileOutputStream(filename);
-            context().printer = new IdealGraphPrinter(context().stream);
-            printer().begin();
-            printer().beginGroup(title, title, method, -1, "Graal");
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    public boolean networkAvailable() {
-        try {
-            Socket s = new Socket(host, port);
-            s.setSoTimeout(10);
-            s.close();
-            return true;
-        } catch (IOException e) {
-            return false;
-        }
-    }
-
-    private void openNetworkPrinter(String title, RiResolvedMethod method) {
-        try {
-            context().socket = new Socket(host, port);
-            if (socket().getInputStream().read() == 'y') {
-                context().stream = new BufferedOutputStream(socket().getOutputStream(), 0x4000);
-            } else {
-                // server currently does not accept any input
-                socket().close();
-                context().socket = null;
-                return;
-            }
-
-            context().printer = new IdealGraphPrinter(context().stream);
-            printer().begin();
-            printer().beginGroup(title, title, method, -1, "Graal");
-            printer().flush();
-            if (socket().getInputStream().read() != 'y') {
-                // server declines input for this method
-                socket().close();
-                context().socket = null;
-                context().stream = null;
-                context().printer = null;
-            }
-        } catch (IOException e) {
-            System.err.println("Error opening connection to " + host + ":" + port + ": " + e);
-
-            if (socket() != null) {
-                try {
-                    socket().close();
-                } catch (IOException ioe) {
-                }
-                context().socket = null;
-            }
-            context().stream = null;
-            context().printer = null;
-        }
-    }
-
-    @Override
-    public void compilationEvent(CompilationEvent event) {
-        boolean lazyStart = false;
-        if (printer() == null && event.hasDebugObject(CompilationEvent.ERROR)) {
-            openPrinter(event.debugObject(GraalCompilation.class), true);
-            lazyStart = true;
-        }
-        Graph graph = event.debugObject(Graph.class);
-        if (printer() != null && graph != null) {
-            printer().print(graph, event.label, true, event.debugObject(IdentifyBlocksPhase.class));
-        }
-        if (lazyStart && printer() != null) {
-            closePrinter();
-        }
-    }
-
-    @Override
-    public void compilationFinished(GraalCompilation compilation) {
-        if (printer() != null) {
-            closePrinter();
-        }
-    }
-
-    private void closePrinter() {
-        assert (printer() != null);
-
-        try {
-            printer().endGroup();
-            printer().end();
-
-            if (socket() != null) {
-                socket().close(); // also closes stream
-            } else {
-                context().stream.close();
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        } finally {
-            context().printer = null;
-            context().stream = null;
-            context().socket = null;
-        }
-    }
-
-    public void printGraphs(String groupTitle, Graph... graphs) {
-        openPrinter(groupTitle, null);
-        if (printer() != null) {
-            int i = 0;
-            for (Graph graph : graphs) {
-                printer().print(graph, "Graph " + i, true);
-                i++;
-            }
-            closePrinter();
-        }
-    }
-
-    public void compilationStarted(String groupTitle) {
-        openPrinter(groupTitle, null);
-    }
-
-    public void printGraph(String graphTitle, Graph graph) {
-        if (printer() != null) {
-            printer().print(graph, graphTitle, true);
-        }
-    }
-
-    public void printSingleGraph(String title, Graph graph) {
-        printSingleGraph(title, title, graph);
-    }
-
-    public void printSingleGraph(String groupTitle, String graphTitle, Graph graph) {
-        openPrinter(groupTitle, null);
-        if (printer() != null) {
-            printer().print(graph, graphTitle, true);
-            closePrinter();
-        }
-    }
-}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/debug/InstructionPrinter.java	Tue Jan 03 16:29:28 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-/*
- * Copyright (c) 2009, 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.debug;
-
-import static com.oracle.max.graal.compiler.debug.InstructionPrinter.InstructionLineColumn.*;
-
-import com.oracle.max.criutils.*;
-import com.oracle.max.graal.nodes.*;
-
-/**
- * A {@link ValueVisitor} for {@linkplain #printInstruction(ValueNode) printing}
- * an {@link FixedWithNextNode} as an expression or statement.
- */
-public class InstructionPrinter {
-
-
-    /**
-     * The columns printed in a tabulated instruction
-     * {@linkplain InstructionPrinter#printInstructionListing(ValueNode) listing}.
-     */
-    public enum InstructionLineColumn {
-        /**
-         * The instruction's bytecode index.
-         */
-        BCI(2, "bci"),
-
-        /**
-         * The instruction's use count.
-         */
-        USE(7, "use"),
-
-        /**
-         * The instruction as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value}.
-         */
-        VALUE(12, "tid"),
-
-        /**
-         * The instruction formatted as an expression or statement.
-         */
-        INSTRUCTION(19, "instr"),
-
-        END(60, "");
-
-        final int position;
-        final String label;
-
-        private InstructionLineColumn(int position, String label) {
-            this.position = position;
-            this.label = label;
-        }
-
-        /**
-         * Prints this column's label to a given stream after padding the stream with '_' characters
-         * until its {@linkplain LogStream#position() position} is equal to this column's position.
-         * @param out the print stream
-         */
-        public void printLabel(LogStream out) {
-            out.fillTo(position + out.indentationLevel(), '_');
-            out.print(label);
-        }
-
-        /**
-         * Prints space characters to a given stream until its {@linkplain LogStream#position() position}
-         * is equal to this column's position.
-         * @param out the print stream
-         */
-        public void advance(LogStream out) {
-            out.fillTo(position + out.indentationLevel(), ' ');
-        }
-    }
-
-    private final LogStream out;
-
-    public InstructionPrinter(LogStream out) {
-        this.out = out;
-    }
-
-    public LogStream out() {
-        return out;
-    }
-
-    /**
-     * Prints a header for the tabulated data printed by {@link #printInstructionListing(ValueNode)}.
-     */
-    public void printInstructionListingHeader() {
-        BCI.printLabel(out);
-        USE.printLabel(out);
-        VALUE.printLabel(out);
-        INSTRUCTION.printLabel(out);
-        END.printLabel(out);
-        out.println();
-    }
-
-    /**
-     * Prints an instruction listing on one line. The instruction listing is composed of the
-     * columns specified by {@link InstructionLineColumn}.
-     *
-     * @param instruction the instruction to print
-     */
-    public void printInstructionListing(ValueNode instruction) {
-        int indentation = out.indentationLevel();
-        out.fillTo(BCI.position + indentation, ' ').
-             print(0).
-             fillTo(USE.position + indentation, ' ').
-             print("0").
-             fillTo(VALUE.position + indentation, ' ').
-             print(ValueUtil.valueString(instruction)).
-             fillTo(INSTRUCTION.position + indentation, ' ');
-        printInstruction(instruction);
-        if (instruction instanceof StateSplit) {
-            out.print("  [state: " + ((StateSplit) instruction).stateAfter() + "]");
-        }
-        out.println();
-    }
-
-    public void printInstruction(ValueNode node) {
-        out.print(node.toString());
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/InstructionPrinter.java	Tue Jan 03 16:44:31 2012 +0100
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2009, 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.gen;
+
+import static com.oracle.max.graal.compiler.gen.InstructionPrinter.InstructionLineColumn.*;
+
+import com.oracle.max.criutils.*;
+import com.oracle.max.graal.nodes.*;
+
+/**
+ * A {@link ValueVisitor} for {@linkplain #printInstruction(ValueNode) printing}
+ * an {@link FixedWithNextNode} as an expression or statement.
+ */
+public class InstructionPrinter {
+
+
+    /**
+     * The columns printed in a tabulated instruction
+     * {@linkplain InstructionPrinter#printInstructionListing(ValueNode) listing}.
+     */
+    public enum InstructionLineColumn {
+        /**
+         * The instruction's bytecode index.
+         */
+        BCI(2, "bci"),
+
+        /**
+         * The instruction's use count.
+         */
+        USE(7, "use"),
+
+        /**
+         * The instruction as a {@linkplain com.oracle.max.graal.compiler.util.Util#valueString(com.oracle.max.graal.compiler.ir.Value) value}.
+         */
+        VALUE(12, "tid"),
+
+        /**
+         * The instruction formatted as an expression or statement.
+         */
+        INSTRUCTION(19, "instr"),
+
+        END(60, "");
+
+        final int position;
+        final String label;
+
+        private InstructionLineColumn(int position, String label) {
+            this.position = position;
+            this.label = label;
+        }
+
+        /**
+         * Prints this column's label to a given stream after padding the stream with '_' characters
+         * until its {@linkplain LogStream#position() position} is equal to this column's position.
+         * @param out the print stream
+         */
+        public void printLabel(LogStream out) {
+            out.fillTo(position + out.indentationLevel(), '_');
+            out.print(label);
+        }
+
+        /**
+         * Prints space characters to a given stream until its {@linkplain LogStream#position() position}
+         * is equal to this column's position.
+         * @param out the print stream
+         */
+        public void advance(LogStream out) {
+            out.fillTo(position + out.indentationLevel(), ' ');
+        }
+    }
+
+    private final LogStream out;
+
+    public InstructionPrinter(LogStream out) {
+        this.out = out;
+    }
+
+    public LogStream out() {
+        return out;
+    }
+
+    /**
+     * Prints a header for the tabulated data printed by {@link #printInstructionListing(ValueNode)}.
+     */
+    public void printInstructionListingHeader() {
+        BCI.printLabel(out);
+        USE.printLabel(out);
+        VALUE.printLabel(out);
+        INSTRUCTION.printLabel(out);
+        END.printLabel(out);
+        out.println();
+    }
+
+    /**
+     * Prints an instruction listing on one line. The instruction listing is composed of the
+     * columns specified by {@link InstructionLineColumn}.
+     *
+     * @param instruction the instruction to print
+     */
+    public void printInstructionListing(ValueNode instruction) {
+        int indentation = out.indentationLevel();
+        out.fillTo(BCI.position + indentation, ' ').
+             print(0).
+             fillTo(USE.position + indentation, ' ').
+             print("0").
+             fillTo(VALUE.position + indentation, ' ').
+             print(ValueUtil.valueString(instruction)).
+             fillTo(INSTRUCTION.position + indentation, ' ');
+        printInstruction(instruction);
+        if (instruction instanceof StateSplit) {
+            out.print("  [state: " + ((StateSplit) instruction).stateAfter() + "]");
+        }
+        out.println();
+    }
+
+    public void printInstruction(ValueNode node) {
+        out.print(node.toString());
+    }
+}
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Tue Jan 03 16:29:28 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/gen/LIRGenerator.java	Tue Jan 03 16:44:31 2012 +0100
@@ -40,7 +40,6 @@
 import com.oracle.max.graal.compiler.*;
 import com.oracle.max.graal.compiler.alloc.*;
 import com.oracle.max.graal.compiler.alloc.OperandPool.VariableFlag;
-import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.graphbuilder.*;
 import com.oracle.max.graal.compiler.lir.*;
 import com.oracle.max.graal.compiler.schedule.*;
--- a/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graphbuilder/BytecodeLookupSwitch.java	Tue Jan 03 16:29:28 2012 +0100
+++ b/graal/com.oracle.max.graal.compiler/src/com/oracle/max/graal/compiler/graphbuilder/BytecodeLookupSwitch.java	Tue Jan 03 16:44:31 2012 +0100
@@ -25,7 +25,7 @@
 /**
  * A utility for processing {@link Bytecodes#LOOKUPSWITCH} bytecodes.
  */
-public class BytecodeLookupSwitch extends BytecodeSwitch {
+class BytecodeLookupSwitch extends BytecodeSwitch {
     private static final int OFFSET_TO_NUMBER_PAIRS = 4;
     private static final int OFFSET_TO_FIRST_PAIR_MATCH = 8;
     private static final int OFFSET_TO_FIRST_PAIR_OFFSET = 12;
--- a/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/CompilerImpl.java	Tue Jan 03 16:29:28 2012 +0100
+++ b/graal/com.oracle.max.graal.hotspot/src/com/oracle/max/graal/hotspot/CompilerImpl.java	Tue Jan 03 16:44:31 2012 +0100
@@ -30,10 +30,12 @@
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.cri.xir.*;
 import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.observer.*;
 import com.oracle.max.graal.cri.*;
 import com.oracle.max.graal.hotspot.logging.*;
 import com.oracle.max.graal.hotspot.ri.*;
 import com.oracle.max.graal.hotspot.server.*;
+import com.oracle.max.graal.printer.*;
 
 /**
  * Singleton class holding the instance of the GraalCompiler.
@@ -212,6 +214,18 @@
     public HotSpotRuntime getRuntime() {
         if (runtime == null) {
             context = new GraalContext("Virtual Machine Compiler");
+            if (GraalOptions.PrintCFGToFile) {
+                context.addCompilationObserver(new CFGPrinterObserver());
+            }
+            if (GraalOptions.PrintIdealGraphLevel != 0 || GraalOptions.Plot || GraalOptions.PlotOnError) {
+                CompilationObserver observer;
+                if (GraalOptions.PrintIdealGraphFile) {
+                    observer = new IdealGraphPrinterObserver();
+                } else {
+                    observer = new IdealGraphPrinterObserver(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort);
+                }
+                context.addCompilationObserver(observer);
+            }
             runtime = new HotSpotRuntime(context, config, this);
         }
         return runtime;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/BasicIdealGraphPrinter.java	Tue Jan 03 16:44:31 2012 +0100
@@ -0,0 +1,303 @@
+/*
+ * 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.printer;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+/**
+ * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific data structures.
+ */
+public class BasicIdealGraphPrinter {
+
+    /**
+     * Edge between two nodes.
+     */
+    public static class Edge {
+        final String from;
+        final int fromIndex;
+        final String to;
+        final int toIndex;
+        final String label;
+
+        public Edge(String from, int fromIndex, String to, int toIndex, String label) {
+            assert (from != null && to != null);
+            this.from = from;
+            this.fromIndex = fromIndex;
+            this.to = to;
+            this.toIndex = toIndex;
+            this.label = label;
+        }
+
+        @Override
+        public int hashCode() {
+            int h = from.hashCode() ^ to.hashCode();
+            h = 3 * h + fromIndex;
+            h = 5 * h + toIndex;
+            if (label != null) {
+                h ^= label.hashCode();
+            }
+            return h;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof Edge) {
+                Edge other = (Edge) obj;
+                return from.equals(other.from)
+                        && fromIndex == other.fromIndex
+                        && to.equals(other.to)
+                        && toIndex == other.toIndex
+                        && (label == other.label || (label != null && label.equals(other.label)));
+            }
+            return false;
+        }
+    }
+
+    private final PrintStream stream;
+
+    /**
+     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
+     */
+    public BasicIdealGraphPrinter(OutputStream stream) {
+        this.stream = new PrintStream(stream);
+    }
+
+    /**
+     * Flushes any buffered output.
+     */
+    public void flush() {
+        stream.flush();
+    }
+
+    /**
+     * Starts a new graph document.
+     */
+    public void begin() {
+        stream.println("<graphDocument>");
+    }
+
+    public void beginGroup() {
+        stream.println("<group>");
+    }
+
+    public void beginMethod(String name, String shortName, int bci) {
+        stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci);
+    }
+
+    public void beginBytecodes() {
+        stream.println("  <bytecodes>\n<![CDATA[");
+    }
+
+    public void printBytecode(int bci, String mnemonic, int[] extra) {
+        stream.print(bci);
+        stream.print(' ');
+        stream.print(mnemonic);
+        if (extra != null) {
+            for (int b : extra) {
+                stream.print(' ');
+                stream.print(b);
+            }
+        }
+        stream.println();
+    }
+
+    public void endBytecodes() {
+        stream.println("  ]]></bytecodes>");
+    }
+
+    public void endMethod() {
+        stream.println(" </method>");
+    }
+
+    public void beginGraph(String title) {
+        stream.printf(" <graph name='%s'>%n", escape(title));
+    }
+
+    public void beginProperties() {
+        stream.print("<properties>");
+    }
+
+    public void printProperty(String name, String value) {
+        stream.printf("<p name='%s'>%s</p>", escape(name), escape(value));
+    }
+
+    public void endProperties() {
+        stream.print("</properties>");
+    }
+
+    public void printProperties(Map<String, String> properties) {
+        beginProperties();
+        for (Entry<String, String> entry : properties.entrySet()) {
+            printProperty(entry.getKey(), entry.getValue());
+        }
+        endProperties();
+    }
+
+    public void beginNodes() {
+        stream.println("  <nodes>");
+    }
+
+    public void beginNode(String id) {
+        stream.printf("   <node id='%s'>", escape(id));
+    }
+
+    public void endNode() {
+        stream.println("   </node>");
+    }
+
+    public void printNode(String id, Map<String, String> properties) {
+        beginNode(id);
+        if (properties != null) {
+            printProperties(properties);
+        }
+        endNode();
+    }
+
+    public void endNodes() {
+        stream.println("  </nodes>");
+    }
+
+    public void beginEdges() {
+        stream.println("  <edges>");
+    }
+
+    public void printEdge(Edge edge) {
+        stream.printf("   <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label));
+    }
+
+    public void endEdges() {
+        stream.println("  </edges>");
+    }
+
+    public void beginControlFlow() {
+        stream.println("  <controlFlow>");
+    }
+
+    public void beginBlock(String name) {
+        stream.printf("   <block name='%s'>%n", escape(name));
+    }
+
+    public void beginSuccessors() {
+        stream.println("    <successors>");
+    }
+
+    public void printSuccessor(String name) {
+        stream.printf("     <successor name='%s'/>%n", escape(name));
+    }
+
+    public void endSuccessors() {
+        stream.println("    </successors>");
+    }
+
+    public void beginBlockNodes() {
+        stream.println("    <nodes>");
+    }
+
+    public void printBlockNode(String nodeId) {
+        stream.printf("     <node id='%s'/>%n", escape(nodeId));
+    }
+
+    public void endBlockNodes() {
+        stream.println("    </nodes>");
+    }
+
+    public void endBlock() {
+        stream.println("   </block>");
+    }
+
+    public void endControlFlow() {
+        stream.println("  </controlFlow>");
+    }
+
+    public void endGraph() {
+        stream.println(" </graph>");
+    }
+
+    /**
+     * Ends the current group.
+     */
+    public void endGroup() {
+        stream.println("</group>");
+    }
+
+    /**
+     * Finishes the graph document and flushes the output stream.
+     */
+    public void end() {
+        stream.println("</graphDocument>");
+        flush();
+    }
+
+    private static String escape(String s) {
+        StringBuilder str = null;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            switch (c) {
+                case '&':
+                case '<':
+                case '>':
+                case '"':
+                case '\'':
+                    if (str == null) {
+                        str = new StringBuilder();
+                        str.append(s, 0, i);
+                    }
+                    switch(c) {
+                        case '&':
+                            str.append("&amp;");
+                            break;
+                        case '<':
+                            str.append("&lt;");
+                            break;
+                        case '>':
+                            str.append("&gt;");
+                            break;
+                        case '"':
+                            str.append("&quot;");
+                            break;
+                        case '\'':
+                            str.append("&apos;");
+                            break;
+                        default:
+                            assert false;
+                    }
+                    break;
+                default:
+                    if (str != null) {
+                        str.append(c);
+                    }
+                    break;
+            }
+        }
+        if (str == null) {
+            return s;
+        } else {
+            return str.toString();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinter.java	Tue Jan 03 16:44:31 2012 +0100
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.max.graal.printer;
+
+import static com.oracle.max.cri.ci.CiValueUtil.*;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.criutils.*;
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.alloc.*;
+import com.oracle.max.graal.compiler.alloc.Interval.UsePosList;
+import com.oracle.max.graal.compiler.graphbuilder.*;
+import com.oracle.max.graal.compiler.lir.*;
+import com.oracle.max.graal.compiler.schedule.*;
+import com.oracle.max.graal.graph.*;
+import com.oracle.max.graal.graph.Node.*;
+import com.oracle.max.graal.graph.NodeClass.*;
+import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.calc.*;
+
+/**
+ * Utility for printing Graal IR at various compilation phases.
+ */
+class CFGPrinter extends CompilationPrinter {
+
+    public final ByteArrayOutputStream buffer;
+    public final GraalCompilation compilation;
+    public final CiTarget target;
+    public final RiRuntime runtime;
+
+    /**
+     * Creates a control flow graph printer.
+     *
+     * @param buffer where the output generated via this printer shown be written
+     */
+    public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation) {
+        super(buffer);
+        this.buffer = buffer;
+        this.compilation = compilation;
+        this.target = compilation.compiler.target;
+        this.runtime = compilation.compiler.runtime;
+    }
+
+    public CFGPrinter(ByteArrayOutputStream buffer, GraalCompilation compilation, CiTarget target, RiRuntime runtime) {
+        super(buffer);
+        this.buffer = buffer;
+        this.compilation = compilation;
+        this.target = target;
+        this.runtime = runtime;
+    }
+
+    /**
+     * Prints the control flow graph denoted by a given block map.
+     *
+     * @param label A label describing the compilation phase that produced the control flow graph.
+     * @param blockMap A data structure describing the blocks in a method and how they are connected.
+     */
+    public void printCFG(String label, BlockMap blockMap) {
+        begin("cfg");
+        out.print("name \"").print(label).println('"');
+        for (BlockMap.Block block : blockMap.blocks) {
+            begin("block");
+            printBlock(block);
+            end("block");
+        }
+        end("cfg");
+    }
+
+    private void printBlock(BlockMap.Block block) {
+        out.print("name \"B").print(block.startBci).println('"');
+        out.print("from_bci ").println(block.startBci);
+        out.print("to_bci ").println(block.endBci);
+
+        out.println("predecessors ");
+
+        out.print("successors ");
+        for (BlockMap.Block succ : block.successors) {
+            if (!succ.isExceptionEntry) {
+                out.print("\"B").print(succ.startBci).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("xhandlers");
+        for (BlockMap.Block succ : block.successors) {
+            if (succ.isExceptionEntry) {
+                out.print("\"B").print(succ.startBci).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("flags ");
+        if (block.isExceptionEntry) {
+            out.print("\"ex\" ");
+        }
+        if (block.isLoopHeader) {
+            out.print("\"plh\" ");
+        }
+        out.println();
+
+        out.print("loop_depth ").println(Long.bitCount(block.loops));
+    }
+
+
+    /**
+     * Prints the specified list of blocks.
+     *
+     * @param label A label describing the compilation phase that produced the control flow graph.
+     * @param blocks The list of blocks to be printed.
+     * @param printNodes If {@code true} the nodes in the block will be printed.
+     */
+    public void printCFG(String label, List<? extends Block> blocks, boolean printNodes) {
+        begin("cfg");
+        out.print("name \"").print(label).println('"');
+        for (Block block : blocks) {
+            printBlock(block, printNodes);
+        }
+        end("cfg");
+    }
+
+    private void printBlock(Block block, boolean printNodes) {
+        begin("block");
+
+        out.print("name \"").print(blockToString(block)).println('"');
+        out.println("from_bci -1");
+        out.println("to_bci -1");
+
+        out.print("predecessors ");
+        for (Block pred : block.getPredecessors()) {
+            out.print("\"").print(blockToString(pred)).print("\" ");
+        }
+        out.println();
+
+        out.print("successors ");
+        for (Block succ : block.getSuccessors()) {
+            if (!succ.isExceptionBlock()) {
+                out.print("\"").print(blockToString(succ)).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("xhandlers");
+        for (Block succ : block.getSuccessors()) {
+            if (succ.isExceptionBlock()) {
+                out.print("\"").print(blockToString(succ)).print("\" ");
+            }
+        }
+        out.println();
+
+        out.print("flags ");
+        if (block.isLoopHeader()) {
+            out.print("\"llh\" ");
+        }
+        if (block.isLoopEnd()) {
+            out.print("\"lle\" ");
+        }
+        if (block.isExceptionBlock()) {
+            out.print("\"ex\" ");
+        }
+        out.println();
+
+        out.print("loop_index ").println(block.loopIndex());
+        out.print("loop_depth ").println(block.loopDepth());
+
+        if (printNodes) {
+            printNodes(block);
+        }
+
+        if (block instanceof LIRBlock) {
+            printLIR((LIRBlock) block);
+        }
+
+        end("block");
+    }
+
+    private void printNodes(Block block) {
+        begin("IR");
+        out.println("HIR");
+        out.disableIndentation();
+
+        if (block.getPredecessors().size() == 0) {
+            // Currently method parameters are not in the schedule, so print them separately here.
+            for (ValueNode param : block.firstNode().graph().getNodes(LocalNode.class)) {
+                printNode(param);
+            }
+        }
+        if (block.firstNode() instanceof MergeNode) {
+            // Currently phi functions are not in the schedule, so print them separately here.
+            for (ValueNode phi : ((MergeNode) block.firstNode()).phis()) {
+                printNode(phi);
+            }
+        }
+
+        for (Node node : block.getInstructions()) {
+            printNode(node);
+        }
+        out.enableIndentation();
+        end("IR");
+    }
+
+    private void printNode(Node node) {
+        if (node instanceof FixedWithNextNode) {
+            out.print("f ").print(HOVER_START).print("#").print(HOVER_SEP).print("fixed with next").print(HOVER_END).println(COLUMN_END);
+        } else if (node instanceof FixedNode) {
+            out.print("f ").print(HOVER_START).print("*").print(HOVER_SEP).print("fixed").print(HOVER_END).println(COLUMN_END);
+        } else if (node instanceof FloatingNode) {
+            out.print("f ").print(HOVER_START).print("~").print(HOVER_SEP).print("floating").print(HOVER_END).println(COLUMN_END);
+        }
+        if (compilation.nodeOperands != null && node instanceof ValueNode) {
+            CiValue operand = compilation.operand((ValueNode) node);
+            if (operand != null) {
+                out.print("result ").print(operand.toString()).println(COLUMN_END);
+            }
+        }
+        out.print("tid ").print(nodeToString(node)).println(COLUMN_END);
+
+        if (node instanceof StateSplit) {
+            StateSplit stateSplit = (StateSplit) node;
+            if (stateSplit.stateAfter() != null) {
+                String state = stateToString(stateSplit.stateAfter());
+                out.print("st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).println(COLUMN_END);
+            }
+        }
+
+        Map<Object, Object> props = new TreeMap<>(node.getDebugProperties());
+        out.print("d ").print(HOVER_START).print("d").print(HOVER_SEP);
+        out.println("=== Debug Properties ===");
+        for (Map.Entry<Object, Object> entry : props.entrySet()) {
+            out.print(entry.getKey().toString()).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).println();
+        }
+        out.println("=== Inputs ===");
+        printNamedNodes(node, node.inputs().iterator(), "", "\n", null);
+        out.println("=== Succesors ===");
+        printNamedNodes(node, node.successors().iterator(), "", "\n", null);
+        out.println("=== Usages ===");
+        if (!node.usages().isEmpty()) {
+            for (Node usage : node.usages()) {
+                out.print(nodeToString(usage)).print(" ");
+            }
+            out.println();
+        }
+        out.println("=== Predecessor ===");
+        out.print(nodeToString(node.predecessor())).print(" ");
+        out.print(HOVER_END).println(COLUMN_END);
+
+        out.print("instruction ");
+        out.print(HOVER_START).print(node.getNodeClass().shortName()).print(HOVER_SEP).print(node.getClass().getName()).print(HOVER_END).print(" ");
+        printNamedNodes(node, node.inputs().iterator(), "", "", "#NDF");
+        printNamedNodes(node, node.successors().iterator(), "#", "", "#NDF");
+        for (Map.Entry<Object, Object> entry : props.entrySet()) {
+            String key = entry.getKey().toString();
+            if (key.startsWith("data.") && !key.equals("data.stamp")) {
+                out.print(key.substring("data.".length())).print(": ").print(entry.getValue() == null ? "[null]" : entry.getValue().toString()).print(" ");
+            }
+        }
+        out.print(COLUMN_END).print(' ').println(COLUMN_END);
+    }
+
+    private void printNamedNodes(Node node, NodeClassIterator iter, String prefix, String suffix, String hideSuffix) {
+        int lastIndex = -1;
+        while (iter.hasNext()) {
+            Position pos = iter.nextPosition();
+            if (hideSuffix != null && node.getNodeClass().getName(pos).endsWith(hideSuffix)) {
+                continue;
+            }
+
+            if (pos.index != lastIndex) {
+                if (lastIndex != -1) {
+                    out.print(suffix);
+                }
+                out.print(prefix).print(node.getNodeClass().getName(pos)).print(": ");
+                lastIndex = pos.index;
+            }
+            out.print(nodeToString(node.getNodeClass().get(node, pos))).print(" ");
+        }
+        if (lastIndex != -1) {
+            out.print(suffix);
+        }
+    }
+
+    private String stateToString(FrameState state) {
+        StringBuilder buf = new StringBuilder();
+        FrameState curState = state;
+        do {
+            buf.append(CiUtil.toLocation(curState.method(), curState.bci)).append('\n');
+
+            if (curState.stackSize() > 0) {
+                buf.append("stack: ");
+                for (int i = 0; i < curState.stackSize(); i++) {
+                    buf.append(stateValueToString(curState.stackAt(i))).append(' ');
+                }
+                buf.append("\n");
+            }
+
+            if (curState.locksSize() > 0) {
+                buf.append("locks: ");
+                for (int i = 0; i < curState.locksSize(); ++i) {
+                    buf.append(stateValueToString(curState.lockAt(i))).append(' ');
+                }
+                buf.append("\n");
+            }
+
+            buf.append("locals: ");
+            for (int i = 0; i < curState.localsSize(); i++) {
+                buf.append(stateValueToString(curState.localAt(i))).append(' ');
+            }
+            buf.append("\n");
+
+            curState = curState.outerFrameState();
+        } while (curState != null);
+
+        return buf.toString();
+    }
+
+    private String stateValueToString(ValueNode value) {
+        String result = nodeToString(value);
+        if (value != null) {
+            CiValue operand = compilation.operand(value);
+            if (operand != null) {
+                result += ": " + operand;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Prints the LIR for each instruction in a given block.
+     *
+     * @param block the block to print
+     */
+    private void printLIR(LIRBlock block) {
+        List<LIRInstruction> lir = block.lir();
+        if (lir == null) {
+            return;
+        }
+
+        begin("IR");
+        out.println("LIR");
+
+        if (block.phis != null) {
+            CiValue[] results = block.phis.results();
+            for (int i = 0; i < results.length; i++) {
+                out.print("instruction PHI ").print(results[i].toString()).print(" = (");
+                String sep = "";
+                for (LIRBlock pred : block.getLIRPredecessors()) {
+                    out.print(sep).print(block.phis.inputs(pred)[i].toString());
+                    sep = ", ";
+                }
+                out.print(")").print(COLUMN_END).println(COLUMN_END);
+            }
+        }
+
+        for (int i = 0; i < lir.size(); i++) {
+            LIRInstruction inst = lir.get(i);
+            out.printf("nr %4d ", inst.id()).print(COLUMN_END);
+
+            if (inst.info != null) {
+                int level = out.indentationLevel();
+                out.adjustIndentation(-level);
+                String state;
+                if (inst.info.hasDebugInfo()) {
+                    state = debugInfoToString(inst.info.debugInfo().codePos, inst.info.debugInfo().registerRefMap, inst.info.debugInfo().frameRefMap, target.arch);
+                } else {
+                    state = debugInfoToString(inst.info.topFrame, null, null, target.arch);
+                }
+                if (state != null) {
+                    out.print(" st ").print(HOVER_START).print("st").print(HOVER_SEP).print(state).print(HOVER_END).print(COLUMN_END);
+                }
+                out.adjustIndentation(level);
+            }
+
+            out.print(" instruction ").print(inst.toString()).print(COLUMN_END);
+            out.println(COLUMN_END);
+        }
+        end("IR");
+    }
+
+    private String nodeToString(Node node) {
+        if (node == null) {
+            return "-";
+        }
+        String prefix;
+        if (node instanceof BeginNode && compilation != null && compilation.lir() == null) {
+            prefix = "B";
+        } else if (node instanceof ValueNode) {
+            ValueNode value = (ValueNode) node;
+            if (value.kind() == CiKind.Illegal) {
+                prefix = "v";
+            } else {
+                prefix = String.valueOf(value.kind().typeChar);
+            }
+        } else {
+            prefix = "?";
+        }
+        return prefix + node.toString(Verbosity.Id);
+    }
+
+    private String blockToString(Block block) {
+        if (compilation != null && compilation.lir() == null) {
+            // During all the front-end phases, the block schedule is built only for the debug output.
+            // Therefore, the block numbers would be different for every CFG printed -> use the id of the first instruction.
+            return "B" + block.firstNode().toString(Verbosity.Id);
+        } else {
+            // LIR instructions contain references to blocks and these blocks are printed as the blockID -> use the blockID.
+            return "B" + block.blockID();
+        }
+    }
+
+
+    public void printIntervals(String label, Interval[] intervals) {
+        begin("intervals");
+        out.println(String.format("name \"%s\"", label));
+
+        for (Interval interval : intervals) {
+            if (interval != null) {
+                printInterval(interval);
+            }
+        }
+
+        end("intervals");
+    }
+
+    private void printInterval(Interval interval) {
+        out.printf("%s %s ", interval.operand, (isRegister(interval.operand) ? "fixed" : interval.kind().name()));
+        if (isRegister(interval.operand)) {
+            out.printf("\"[%s|%c]\"", interval.operand, interval.operand.kind.typeChar);
+        } else {
+            if (interval.location() != null) {
+                out.printf("\"[%s|%c]\"", interval.location(), interval.location().kind.typeChar);
+            }
+        }
+
+        Interval hint = interval.locationHint(false);
+        out.printf("%s %s ", interval.splitParent().operand, hint != null ? hint.operand : -1);
+
+        // print ranges
+        Range cur = interval.first();
+        while (cur != Range.EndMarker) {
+            out.printf("[%d, %d[", cur.from, cur.to);
+            cur = cur.next;
+            assert cur != null : "range list not closed with range sentinel";
+        }
+
+        // print use positions
+        int prev = 0;
+        UsePosList usePosList = interval.usePosList();
+        for (int i = usePosList.size() - 1; i >= 0; --i) {
+            assert prev < usePosList.usePos(i) : "use positions not sorted";
+            out.printf("%d %s ", usePosList.usePos(i), usePosList.registerPriority(i));
+            prev = usePosList.usePos(i);
+        }
+
+        out.printf(" \"%s\"", interval.spillState());
+        out.println();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/CFGPrinterObserver.java	Tue Jan 03 16:44:31 2012 +0100
@@ -0,0 +1,138 @@
+/*
+ * 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.printer;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.max.cri.ci.*;
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.criutils.*;
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.alloc.*;
+import com.oracle.max.graal.compiler.graphbuilder.*;
+import com.oracle.max.graal.compiler.lir.*;
+import com.oracle.max.graal.compiler.observer.*;
+import com.oracle.max.graal.compiler.schedule.*;
+import com.oracle.max.graal.graph.*;
+import com.oracle.max.graal.nodes.*;
+
+/**
+ * Observes compilation events and uses {@link CFGPrinter} to produce a control flow graph for the <a
+ * href="http://java.net/projects/c1visualizer/">C1 Visualizer</a>.
+ */
+public class CFGPrinterObserver implements CompilationObserver {
+
+    /**
+     * A thread local stack of {@link CFGPrinter}s to support thread-safety and re-entrant compilation.
+     */
+    private ThreadLocal<LinkedList<CFGPrinter>> observations = new ThreadLocal<LinkedList<CFGPrinter>>() {
+        @Override
+        protected java.util.LinkedList<CFGPrinter> initialValue() {
+            return new LinkedList<>();
+        }
+    };
+
+    @Override
+    public void compilationStarted(GraalCompilation compilation) {
+        if (TTY.isSuppressed()) {
+            return;
+        }
+
+        CFGPrinter cfgPrinter = new CFGPrinter(new ByteArrayOutputStream(), compilation);
+        cfgPrinter.printCompilation(compilation.method);
+        observations.get().push(cfgPrinter);
+    }
+
+    @Override
+    public void compilationEvent(CompilationEvent event) {
+        if (TTY.isSuppressed()) {
+            return;
+        }
+        CFGPrinter cfgPrinter = observations.get().peek();
+        if (cfgPrinter == null) {
+            return;
+        }
+
+        RiRuntime runtime = cfgPrinter.runtime;
+        BlockMap blockMap = event.debugObject(BlockMap.class);
+        Graph graph = event.debugObject(Graph.class);
+        IdentifyBlocksPhase schedule = event.debugObject(IdentifyBlocksPhase.class);
+        LIR lir = event.debugObject(LIR.class);
+        LinearScan allocator = event.debugObject(LinearScan.class);
+        Interval[] intervals = event.debugObject(Interval[].class);
+        CiTargetMethod targetMethod = event.debugObject(CiTargetMethod.class);
+
+        if (blockMap != null) {
+            cfgPrinter.printCFG(event.label, blockMap);
+            cfgPrinter.printBytecodes(runtime.disassemble(blockMap.method));
+        }
+        if (lir != null) {
+            cfgPrinter.printCFG(event.label, lir.codeEmittingOrder(), graph != null);
+            if (targetMethod != null) {
+                cfgPrinter.printMachineCode(runtime.disassemble(targetMethod), null);
+            }
+        } else if (graph != null) {
+            List<? extends Block> blocks = null;
+            if (schedule == null) {
+                try {
+                    schedule = new IdentifyBlocksPhase(true, LIRBlock.FACTORY);
+                    schedule.apply((StructuredGraph) graph, false);
+                    blocks = schedule.getBlocks();
+
+                    ComputeLinearScanOrder clso = new ComputeLinearScanOrder(schedule.getBlocks().size(), schedule.loopCount(), (LIRBlock) schedule.getStartBlock());
+                    blocks = clso.codeEmittingOrder();
+                } catch (Throwable t) {
+                    // nothing to do here...
+                }
+            }
+            if (blocks != null) {
+                cfgPrinter.printCFG(event.label, blocks, true);
+            }
+        }
+        if (allocator != null && intervals != null) {
+            cfgPrinter.printIntervals(event.label, intervals);
+        }
+    }
+
+    @Override
+    public void compilationFinished(GraalCompilation compilation) {
+        if (TTY.isSuppressed()) {
+            return;
+        }
+        CFGPrinter cfgPrinter = observations.get().pop();
+        cfgPrinter.flush();
+
+        OutputStream stream = CompilationPrinter.globalOut();
+        if (stream != null) {
+            synchronized (stream) {
+                try {
+                    stream.write(cfgPrinter.buffer.toByteArray());
+                    stream.flush();
+                } catch (IOException e) {
+                    TTY.println("WARNING: Error writing CFGPrinter output: %s", e);
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinter.java	Tue Jan 03 16:44:31 2012 +0100
@@ -0,0 +1,419 @@
+/*
+ * 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.printer;
+
+import java.io.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.graphbuilder.*;
+import com.oracle.max.graal.compiler.schedule.*;
+import com.oracle.max.graal.compiler.util.*;
+import com.oracle.max.graal.compiler.util.LoopUtil.Loop;
+import com.oracle.max.graal.graph.*;
+import com.oracle.max.graal.graph.Node.Verbosity;
+import com.oracle.max.graal.graph.NodeClass.NodeClassIterator;
+import com.oracle.max.graal.graph.NodeClass.Position;
+import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.nodes.loop.*;
+import com.oracle.max.graal.printer.BasicIdealGraphPrinter.*;
+
+/**
+ * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the <a
+ * href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
+ */
+class IdealGraphPrinter {
+
+    private final BasicIdealGraphPrinter printer;
+    private final HashSet<Class<?>> omittedClasses = new HashSet<>();
+    private final Set<Node> noBlockNodes = new HashSet<>();
+
+    /**
+     * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
+     */
+    public IdealGraphPrinter(OutputStream stream) {
+        this.printer = new BasicIdealGraphPrinter(stream);
+    }
+
+    /**
+     * Adds a node class that is omitted in the output.
+     */
+    public void addOmittedClass(Class<?> clazz) {
+        omittedClasses.add(clazz);
+    }
+
+    /**
+     * Flushes any buffered output.
+     */
+    public void flush() {
+        printer.flush();
+    }
+
+    /**
+     * Starts a new graph document.
+     */
+    public void begin() {
+        printer.begin();
+    }
+
+    /**
+     * Starts a new group of graphs with the given name, short name and method byte code index (BCI) as properties.
+     */
+    public void beginGroup(String name, String shortName, RiResolvedMethod method, int bci, String origin) {
+        printer.beginGroup();
+        printer.beginProperties();
+        printer.printProperty("name", name);
+        printer.printProperty("origin", origin);
+        printer.endProperties();
+        printer.beginMethod(name, shortName, bci);
+        if (GraalOptions.PrintIdealGraphBytecodes && method != null) {
+            printer.beginBytecodes();
+            BytecodeStream bytecodes = new BytecodeStream(method.code());
+            while (bytecodes.currentBC() != Bytecodes.END) {
+                int startBCI = bytecodes.currentBCI();
+                String mnemonic = Bytecodes.nameOf(bytecodes.currentBC());
+                int[] extra = null;
+                if (bytecodes.nextBCI() > startBCI + 1) {
+                    extra = new int[bytecodes.nextBCI() - (startBCI + 1)];
+                    for (int i = 0; i < extra.length; i++) {
+                        extra[i] = bytecodes.readUByte(startBCI + 1 + i);
+                    }
+                }
+                printer.printBytecode(startBCI, mnemonic, extra);
+                bytecodes.next();
+            }
+            printer.endBytecodes();
+        }
+        printer.endMethod();
+    }
+
+    /**
+     * Ends the current group.
+     */
+    public void endGroup() {
+        printer.endGroup();
+    }
+
+    /**
+     * Finishes the graph document and flushes the output stream.
+     */
+    public void end() {
+        printer.end();
+    }
+
+    public void print(Graph graph, String title, boolean shortNames) {
+        print(graph, title, shortNames, null);
+    }
+
+    /**
+     * Prints an entire {@link Graph} with the specified title, optionally using short names for nodes.
+     */
+    public void print(Graph graph, String title, boolean shortNames, IdentifyBlocksPhase predefinedSchedule) {
+        printer.beginGraph(title);
+        noBlockNodes.clear();
+        IdentifyBlocksPhase schedule = predefinedSchedule;
+        if (schedule == null) {
+            try {
+                schedule = new IdentifyBlocksPhase(true);
+                schedule.apply((StructuredGraph) graph, false);
+            } catch (Throwable t) {
+                // nothing to do here...
+            }
+        }
+        List<Loop> loops = null;
+        try {
+            loops = LoopUtil.computeLoops((StructuredGraph) graph);
+            // loop.nodes() does some more calculations which may fail, so execute this here as well (result is cached)
+            if (loops != null) {
+                for (Loop loop : loops) {
+                    loop.nodes();
+                }
+            }
+        } catch (Throwable t) {
+            t.printStackTrace();
+            loops = null;
+        }
+
+        printer.beginNodes();
+        List<Edge> edges = printNodes(graph, shortNames, schedule == null ? null : schedule.getNodeToBlock(), loops);
+        printer.endNodes();
+
+        printer.beginEdges();
+        for (Edge edge : edges) {
+            printer.printEdge(edge);
+        }
+        printer.endEdges();
+
+        if (schedule != null) {
+            printer.beginControlFlow();
+            for (Block block : schedule.getBlocks()) {
+                printBlock(graph, block, schedule.getNodeToBlock());
+            }
+            printNoBlock();
+            printer.endControlFlow();
+        }
+
+        printer.endGraph();
+        flush();
+    }
+
+    private List<Edge> printNodes(Graph graph, boolean shortNames, NodeMap<Block> nodeToBlock, List<Loop> loops) {
+        ArrayList<Edge> edges = new ArrayList<>();
+        NodeBitMap loopExits = graph.createNodeBitMap();
+        if (loops != null) {
+            for (Loop loop : loops) {
+                loopExits.setUnion(loop.exits());
+            }
+        }
+
+        NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap();
+        NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap();
+        NodeMap<Set<String>> bits = graph.createNodeMap();
+// TODO This code was never reachable, since there was no code putting a NodeMap or NodeBitMap into the debugObjects.
+// If you need to reactivate this code, put the mapping from names to values into a helper object and register it in the new debugObjects array.
+//
+//        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));
+//                        Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node);
+//                        if (nodeColorStrings == null) {
+//                            nodeColorStrings = new HashSet<Entry<String, String>>();
+//                            colorsToString.put(node, nodeColorStrings);
+//                        }
+//                        nodeColorStrings.add(new SimpleImmutableEntry<String, String>(name, color.toString()));
+//                    }
+//                } 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()) {
+            if (omittedClasses.contains(node.getClass())) {
+                continue;
+            }
+
+            printer.beginNode(node.toString(Verbosity.Id));
+            printer.beginProperties();
+            printer.printProperty("idx", node.toString(Verbosity.Id));
+
+            Map<Object, Object> props = node.getDebugProperties();
+            if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) {
+                String name;
+                if (shortNames) {
+                    name = node.toString(Verbosity.Name);
+                } else {
+                    name = node.toString();
+                }
+                printer.printProperty("name", name);
+            }
+            printer.printProperty("class", node.getClass().getSimpleName());
+            Block block = nodeToBlock == null ? null : nodeToBlock.get(node);
+            if (block != null) {
+                printer.printProperty("block", Integer.toString(block.blockID()));
+                if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof LocalNode || node instanceof InductionVariableNode) && !block.getInstructions().contains(node)) {
+                    printer.printProperty("notInOwnBlock", "true");
+                }
+            } else {
+                printer.printProperty("block", "noBlock");
+                noBlockNodes.add(node);
+            }
+            if (loopExits.isMarked(node)) {
+                printer.printProperty("loopExit", "true");
+            }
+            StringBuilder sb = new StringBuilder();
+            if (loops != null) {
+                for (Loop loop : loops) {
+                    if (loop.nodes().isMarked(node)) {
+                        if (sb.length() > 0) {
+                            sb.append(", ");
+                        }
+                        sb.append(loop.loopBegin().toString(Verbosity.Id));
+                    }
+                }
+            }
+            if (sb.length() > 0) {
+                printer.printProperty("loops", sb.toString());
+            }
+
+            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();
+                    printer.printProperty(name, Integer.toString(value));
+                }
+            }
+            Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node);
+            if (nodeColorStrings != null) {
+                for (Entry<String, String> color : nodeColorStrings) {
+                    String name = color.getKey();
+                    String value = color.getValue();
+                    printer.printProperty(name, value);
+                }
+            }
+            Set<String> nodeBits = bits.get(node);
+            if (nodeBits != null) {
+                for (String bit : nodeBits) {
+                    printer.printProperty(bit, "true");
+                }
+            }
+
+            for (Entry<Object, Object> entry : props.entrySet()) {
+                String key = entry.getKey().toString();
+                String value = entry.getValue() == null ? "null" : entry.getValue().toString();
+                printer.printProperty(key, value);
+            }
+
+            printer.endProperties();
+            printer.endNode();
+
+            // successors
+            int fromIndex = 0;
+            NodeClassIterator succIter = node.successors().iterator();
+            while (succIter.hasNext()) {
+                Position position = succIter.nextPosition();
+                Node successor = node.getNodeClass().get(node, position);
+                if (successor != null && !omittedClasses.contains(successor.getClass())) {
+                    edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, node.getNodeClass().getName(position)));
+                }
+                fromIndex++;
+            }
+
+            // inputs
+            int toIndex = 1;
+            NodeClassIterator inputIter = node.inputs().iterator();
+            while (inputIter.hasNext()) {
+                Position position = inputIter.nextPosition();
+                Node input = node.getNodeClass().get(node, position);
+                if (input != null && !omittedClasses.contains(input.getClass())) {
+                    edges.add(new Edge(input.toString(Verbosity.Id), input.successors().explicitCount(), node.toString(Verbosity.Id), toIndex, node.getNodeClass().getName(position)));
+                }
+                toIndex++;
+            }
+        }
+
+        return edges;
+    }
+
+    private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) {
+        printer.beginBlock(Integer.toString(block.blockID()));
+        printer.beginSuccessors();
+        for (Block sux : block.getSuccessors()) {
+            if (sux != null) {
+                printer.printSuccessor(Integer.toString(sux.blockID()));
+            }
+        }
+        printer.endSuccessors();
+        printer.beginBlockNodes();
+
+        Set<Node> nodes = new HashSet<>(block.getInstructions());
+
+        if (nodeToBlock != null) {
+            for (Node n : graph.getNodes()) {
+                Block blk = nodeToBlock.get(n);
+                if (blk == block) {
+                    nodes.add(n);
+                }
+            }
+        }
+
+        if (nodes.size() > 0) {
+            // if this is the first block: add all locals to this block
+            if (block.getInstructions().size() > 0 && block.getInstructions().get(0) == ((StructuredGraph) graph).start()) {
+                for (Node node : graph.getNodes()) {
+                    if (node instanceof LocalNode) {
+                        nodes.add(node);
+                    }
+                }
+            }
+
+            // add all framestates and phis to their blocks
+            for (Node node : block.getInstructions()) {
+                if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {
+                    nodes.add(((StateSplit) node).stateAfter());
+                }
+                if (node instanceof MergeNode) {
+                    for (PhiNode phi : ((MergeNode) node).phis()) {
+                        nodes.add(phi);
+                    }
+                    if (node instanceof LoopBeginNode) {
+                        for (InductionVariableNode iv : ((LoopBeginNode) node).inductionVariables()) {
+                            nodes.add(iv);
+                        }
+                    }
+                }
+            }
+
+            for (Node node : nodes) {
+                if (!omittedClasses.contains(node.getClass())) {
+                    printer.printBlockNode(node.toString(Verbosity.Id));
+                }
+            }
+        }
+        printer.endBlockNodes();
+        printer.endBlock();
+    }
+
+    private void printNoBlock() {
+        if (!noBlockNodes.isEmpty()) {
+            printer.beginBlock("noBlock");
+            printer.beginBlockNodes();
+            for (Node node : noBlockNodes) {
+                printer.printBlockNode(node.toString(Verbosity.Id));
+            }
+            printer.endBlockNodes();
+            printer.endBlock();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.max.graal.printer/src/com/oracle/max/graal/printer/IdealGraphPrinterObserver.java	Tue Jan 03 16:44:31 2012 +0100
@@ -0,0 +1,265 @@
+/*
+ * 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.printer;
+
+import java.io.*;
+import java.net.*;
+import java.util.regex.*;
+
+import com.oracle.max.cri.ri.*;
+import com.oracle.max.criutils.*;
+import com.oracle.max.graal.compiler.*;
+import com.oracle.max.graal.compiler.observer.*;
+import com.oracle.max.graal.compiler.schedule.*;
+import com.oracle.max.graal.graph.*;
+
+/**
+ * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation that can be
+ * inspected with the <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
+ */
+public class IdealGraphPrinterObserver implements CompilationObserver {
+
+    private static final Pattern INVALID_CHAR = Pattern.compile("[^A-Za-z0-9_.-]");
+
+    private final String host;
+    private final int port;
+
+    private static class PrintingContext {
+        public IdealGraphPrinter printer;
+        private OutputStream stream;
+        private Socket socket;
+
+    }
+    private final ThreadLocal<PrintingContext> context = new ThreadLocal<PrintingContext>() {
+        @Override
+        protected PrintingContext initialValue() {
+            return new PrintingContext();
+        }
+    };
+
+    /**
+     * Creates a new {@link IdealGraphPrinterObserver} that writes output to a file named after the compiled method.
+     */
+    public IdealGraphPrinterObserver() {
+        this(null, -1);
+    }
+
+    /**
+     * Creates a new {@link IdealGraphPrinterObserver} that sends output to a remote IdealGraphVisualizer instance.
+     */
+    public IdealGraphPrinterObserver(String host, int port) {
+        this.host = host;
+        this.port = port;
+    }
+
+    private PrintingContext context() {
+        return context.get();
+    }
+
+    private IdealGraphPrinter printer() {
+        return context().printer;
+    }
+
+    private Socket socket() {
+        return context().socket;
+    }
+
+    @Override
+    public void compilationStarted(GraalCompilation compilation) {
+        openPrinter(compilation, false);
+    }
+
+    private void openPrinter(GraalCompilation compilation, boolean error) {
+        assert (context().stream == null && printer() == null);
+        if ((!TTY.isSuppressed() && GraalOptions.Plot) || (GraalOptions.PlotOnError && error)) {
+            String name;
+            if (compilation != null) {
+                name = compilation.method.holder().name();
+                name = name.substring(1, name.length() - 1).replace('/', '.');
+                name = name + "." + compilation.method.name();
+            } else {
+                name = "null";
+            }
+
+            openPrinter(name, compilation == null ? null : compilation.method);
+        }
+    }
+
+    private void openPrinter(String title, RiResolvedMethod method) {
+        assert (context().stream == null && printer() == null);
+        if (!TTY.isSuppressed()) {
+            // Use a filter to suppress a recursive attempt to open a printer
+            TTY.Filter filter = new TTY.Filter();
+            try {
+                if (host != null) {
+                    openNetworkPrinter(title, method);
+                } else {
+                    openFilePrinter(title, method);
+                }
+            } finally {
+                filter.remove();
+            }
+        }
+    }
+
+    private void openFilePrinter(String title, RiResolvedMethod method) {
+        String filename = title + ".igv.xml";
+        filename = INVALID_CHAR.matcher(filename).replaceAll("_");
+
+        try {
+            context().stream = new FileOutputStream(filename);
+            context().printer = new IdealGraphPrinter(context().stream);
+            printer().begin();
+            printer().beginGroup(title, title, method, -1, "Graal");
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public boolean networkAvailable() {
+        try {
+            Socket s = new Socket(host, port);
+            s.setSoTimeout(10);
+            s.close();
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    private void openNetworkPrinter(String title, RiResolvedMethod method) {
+        try {
+            context().socket = new Socket(host, port);
+            if (socket().getInputStream().read() == 'y') {
+                context().stream = new BufferedOutputStream(socket().getOutputStream(), 0x4000);
+            } else {
+                // server currently does not accept any input
+                socket().close();
+                context().socket = null;
+                return;
+            }
+
+            context().printer = new IdealGraphPrinter(context().stream);
+            printer().begin();
+            printer().beginGroup(title, title, method, -1, "Graal");
+            printer().flush();
+            if (socket().getInputStream().read() != 'y') {
+                // server declines input for this method
+                socket().close();
+                context().socket = null;
+                context().stream = null;
+                context().printer = null;
+            }
+        } catch (IOException e) {
+            System.err.println("Error opening connection to " + host + ":" + port + ": " + e);
+
+            if (socket() != null) {
+                try {
+                    socket().close();
+                } catch (IOException ioe) {
+                }
+                context().socket = null;
+            }
+            context().stream = null;
+            context().printer = null;
+        }
+    }
+
+    @Override
+    public void compilationEvent(CompilationEvent event) {
+        boolean lazyStart = false;
+        if (printer() == null && event.hasDebugObject(CompilationEvent.ERROR)) {
+            openPrinter(event.debugObject(GraalCompilation.class), true);
+            lazyStart = true;
+        }
+        Graph graph = event.debugObject(Graph.class);
+        if (printer() != null && graph != null) {
+            printer().print(graph, event.label, true, event.debugObject(IdentifyBlocksPhase.class));
+        }
+        if (lazyStart && printer() != null) {
+            closePrinter();
+        }
+    }
+
+    @Override
+    public void compilationFinished(GraalCompilation compilation) {
+        if (printer() != null) {
+            closePrinter();
+        }
+    }
+
+    private void closePrinter() {
+        assert (printer() != null);
+
+        try {
+            printer().endGroup();
+            printer().end();
+
+            if (socket() != null) {
+                socket().close(); // also closes stream
+            } else {
+                context().stream.close();
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            context().printer = null;
+            context().stream = null;
+            context().socket = null;
+        }
+    }
+
+    public void printGraphs(String groupTitle, Graph... graphs) {
+        openPrinter(groupTitle, null);
+        if (printer() != null) {
+            int i = 0;
+            for (Graph graph : graphs) {
+                printer().print(graph, "Graph " + i, true);
+                i++;
+            }
+            closePrinter();
+        }
+    }
+
+    public void compilationStarted(String groupTitle) {
+        openPrinter(groupTitle, null);
+    }
+
+    public void printGraph(String graphTitle, Graph graph) {
+        if (printer() != null) {
+            printer().print(graph, graphTitle, true);
+        }
+    }
+
+    public void printSingleGraph(String title, Graph graph) {
+        printSingleGraph(title, title, graph);
+    }
+
+    public void printSingleGraph(String groupTitle, String graphTitle, Graph graph) {
+        openPrinter(groupTitle, null);
+        if (printer() != null) {
+            printer().print(graph, graphTitle, true);
+            closePrinter();
+        }
+    }
+}
--- a/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/Snippets.java	Tue Jan 03 16:29:28 2012 +0100
+++ b/graal/com.oracle.max.graal.snippets/src/com/oracle/max/graal/snippets/Snippets.java	Tue Jan 03 16:44:31 2012 +0100
@@ -27,7 +27,6 @@
 import com.oracle.max.cri.ci.*;
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.graphbuilder.*;
 import com.oracle.max.graal.compiler.observer.*;
 import com.oracle.max.graal.compiler.phases.*;
@@ -37,6 +36,7 @@
 import com.oracle.max.graal.nodes.*;
 import com.oracle.max.graal.nodes.extended.*;
 import com.oracle.max.graal.nodes.java.*;
+import com.oracle.max.graal.printer.*;
 
 /**
  * Utilities for snippet installation and management.
--- a/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphTest.java	Tue Jan 03 16:29:28 2012 +0100
+++ b/graal/com.oracle.max.graal.tests/src/com/oracle/max/graal/compiler/tests/GraphTest.java	Tue Jan 03 16:44:31 2012 +0100
@@ -30,10 +30,10 @@
 
 import com.oracle.max.cri.ri.*;
 import com.oracle.max.graal.compiler.*;
-import com.oracle.max.graal.compiler.debug.*;
 import com.oracle.max.graal.compiler.graphbuilder.*;
 import com.oracle.max.graal.cri.*;
 import com.oracle.max.graal.nodes.*;
+import com.oracle.max.graal.printer.*;
 
 /**
  * Base class for Graal compiler unit tests. These are white box tests
--- a/mx/projects	Tue Jan 03 16:29:28 2012 +0100
+++ b/mx/projects	Tue Jan 03 16:44:31 2012 +0100
@@ -44,7 +44,7 @@
 # graal.hotspot
 project@com.oracle.max.graal.hotspot@subDir=graal
 project@com.oracle.max.graal.hotspot@sourceDirs=src
-project@com.oracle.max.graal.hotspot@dependencies=com.oracle.max.graal.snippets,com.oracle.max.asmdis
+project@com.oracle.max.graal.hotspot@dependencies=com.oracle.max.graal.snippets,com.oracle.max.asmdis,com.oracle.max.graal.printer
 project@com.oracle.max.graal.hotspot@checkstyle=com.oracle.max.graal.graph
 
 # graal.graph
@@ -55,7 +55,7 @@
 # graal.snippets
 project@com.oracle.max.graal.snippets@subDir=graal
 project@com.oracle.max.graal.snippets@sourceDirs=src,test
-project@com.oracle.max.graal.snippets@dependencies=com.oracle.max.graal.compiler
+project@com.oracle.max.graal.snippets@dependencies=com.oracle.max.graal.printer,com.oracle.max.graal.compiler
 project@com.oracle.max.graal.snippets@checkstyle=com.oracle.max.graal.graph
 
 # graal.nodes
@@ -70,10 +70,16 @@
 project@com.oracle.max.graal.compiler@dependencies=com.oracle.max.asm,com.oracle.max.graal.nodes
 project@com.oracle.max.graal.compiler@checkstyle=com.oracle.max.graal.graph
 
+# graal.printer
+project@com.oracle.max.graal.printer@subDir=graal
+project@com.oracle.max.graal.printer@sourceDirs=src
+project@com.oracle.max.graal.printer@dependencies=com.oracle.max.graal.compiler,com.oracle.max.asm,com.oracle.max.graal.nodes
+project@com.oracle.max.graal.printer@checkstyle=com.oracle.max.graal.graph
+
 # graal.test
 project@com.oracle.max.graal.tests@subDir=graal
 project@com.oracle.max.graal.tests@sourceDirs=src
-project@com.oracle.max.graal.tests@dependencies=com.oracle.max.graal.compiler
+project@com.oracle.max.graal.tests@dependencies=com.oracle.max.graal.compiler,com.oracle.max.graal.printer
 project@com.oracle.max.graal.tests@checkstyle=com.oracle.max.graal.graph
 
 # max.asm