changeset 5810:bc237d8b6f99

Add binary graph dumping to compiler (-G:+PrintBinaryGraphs) Add binary graph handling in IGV (runs in parallel with xml graph handling) Add option to disable CFG files (c1 visualizer) dumping Include partial schedule in igv dumps when graph is not schedulable
author Gilles Duboscq <duboscq@ssw.jku.at>
date Mon, 09 Jul 2012 14:15:55 +0200
parents cb5fd04e95b3
children 6a725f3c4bb0
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinterDumpHandler.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryClient.java src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryServer.java src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java
diffstat 17 files changed, 1341 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Jul 09 14:15:55 2012 +0200
@@ -135,11 +135,13 @@
     public static boolean DumpOnError                        = ____;
 
     // Ideal graph visualizer output settings
+    public static boolean PrintBinaryGraphs                  = ____;
+    public static boolean PrintCFG                           = true;
     public static int     PlotLevel                          = 3;
-    public static int     PrintIdealGraphLevel               = 0;
     public static boolean PrintIdealGraphFile                = ____;
     public static String  PrintIdealGraphAddress             = "127.0.0.1";
     public static int     PrintIdealGraphPort                = 4444;
+    public static int     PrintBinaryGraphPort               = 4445;
 
     // Other printing settings
     public static boolean PrintQueue                         = ____;
@@ -210,6 +212,7 @@
     public static boolean OptLivenessAnalysis                = true;
     public static boolean OptLoopTransform                   = true;
     public static boolean OptSafepointElimination            = true;
+    public static boolean FloatingReads                      = true;
 
     /**
      * Insert a counter in the method prologue to track the most frequently called methods that were compiled by Graal.
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java	Mon Jul 09 14:15:55 2012 +0200
@@ -27,6 +27,14 @@
 import com.oracle.graal.graph.*;
 import com.oracle.graal.nodes.*;
 
+/**
+ * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a specified fixed node.<br>
+ * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode}, {@link MergeNode}...) and the {@link FixedWithNextNode#next() next} pointers
+ * of {@link FixedWithNextNode}.<br>
+ * While iterating it maintains a user-defined state by calling the methods available in {@link MergeableState}.
+ *
+ * @param <T> the type of {@link MergeableState} handled by this PostOrderNodeIterator
+ */
 public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
 
     private final NodeBitMap visitedEnds;
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Jul 09 14:15:55 2012 +0200
@@ -311,6 +311,11 @@
                 }
                 return super.filter(clazz);
             }
+
+            @Override
+            public int count() {
+                return getNodeCount();
+            }
         };
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Jul 09 14:15:55 2012 +0200
@@ -489,6 +489,12 @@
         }
     }
 
+
+    @Deprecated
+    public int getId() {
+        return id;
+    }
+
     @Override
     public void formatTo(Formatter formatter, int flags, int width, int precision) {
         if ((flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Jul 09 14:15:55 2012 +0200
@@ -570,17 +570,6 @@
                 } else {
                     assert false : "unhandled property type: " + type;
                 }
-            } else {
-                value = unsafe.getObject(node, dataOffsets[i]);
-                if (type.isArray()) {
-                    if (!type.getComponentType().isPrimitive()) {
-                        value = Arrays.toString((Object[]) value);
-                    } else if (type.getComponentType() == Integer.TYPE) {
-                        value = Arrays.toString((int[]) value);
-                    } else if (type.getComponentType() == Double.TYPE) {
-                        value = Arrays.toString((double[]) value);
-                    }
-                }
             }
             properties.put("data." + dataNames[i], value);
         }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Mon Jul 09 14:15:55 2012 +0200
@@ -64,13 +64,22 @@
         if (logFilter != null || meterFilter != null || timerFilter != null || dumpFilter != null || methodFilter != null) {
             TTY.println(Thread.currentThread().getName() + ": " + toString());
         }
-
-        if (GraalOptions.PrintIdealGraphFile) {
-            dumpHandlers.add(new IdealGraphPrinterDumpHandler());
+        if (GraalOptions.PrintBinaryGraphs) {
+            if (GraalOptions.PrintIdealGraphFile) {
+                dumpHandlers.add(new BinaryGraphPrinterDumpHandler());
+            } else {
+                dumpHandlers.add(new BinaryGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintBinaryGraphPort));
+            }
         } else {
-            dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort));
+            if (GraalOptions.PrintIdealGraphFile) {
+                dumpHandlers.add(new IdealGraphPrinterDumpHandler());
+            } else {
+                dumpHandlers.add(new IdealGraphPrinterDumpHandler(GraalOptions.PrintIdealGraphAddress, GraalOptions.PrintIdealGraphPort));
+            }
         }
-        dumpHandlers.add(new CFGPrinterObserver());
+        if (GraalOptions.PrintCFG) {
+            dumpHandlers.add(new CFGPrinterObserver());
+        }
         this.output = output;
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java	Mon Jul 09 14:15:55 2012 +0200
@@ -53,7 +53,6 @@
     }
 
     public int getId() {
-        assert id >= 0;
         return id;
     }
 
--- a/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java	Mon Jul 09 14:15:55 2012 +0200
@@ -25,6 +25,7 @@
 public class CFGVerifier {
     public static boolean verify(ControlFlowGraph cfg) {
         for (Block block : cfg.getBlocks()) {
+            assert block.getId() >= 0;
             assert cfg.getBlocks()[block.getId()] == block;
 
             for (Block pred : block.getPredecessors()) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java	Mon Jul 09 14:15:55 2012 +0200
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.printer;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.util.*;
+import java.util.Map.Entry;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.schedule.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.graph.NodeClass.NodeClassIterator;
+import com.oracle.graal.graph.NodeClass.Position;
+import com.oracle.graal.lir.cfg.*;
+import com.oracle.graal.nodes.*;
+
+public class BinaryGraphPrinter {
+    private static final int CONSTANT_POOL_MAX_SIZE = 2000;
+
+    private static final int BEGIN_GROUP = 0x00;
+    private static final int BEGIN_GRAPH = 0x01;
+    private static final int CLOSE_GROUP = 0x02;
+
+    private static final int POOL_NULL = -1;
+    private static final int POOL_NEW = 0x00;
+    private static final int POOL_STRING = 0x01;
+    private static final int POOL_ENUM = 0x02;
+    private static final int POOL_CLASS = 0x03;
+    private static final int POOL_METHOD = 0x04;
+
+    private static final int PROPERTY_POOL = 0x00;
+    private static final int PROPERTY_INT = 0x01;
+    private static final int PROPERTY_LONG = 0x02;
+    private static final int PROPERTY_DOUBLE = 0x03;
+    private static final int PROPERTY_FLOAT = 0x04;
+    private static final int PROPERTY_TRUE = 0x05;
+    private static final int PROPERTY_FALSE = 0x06;
+    private static final int PROPERTY_ARRAY = 0x07;
+
+    private static final int KLASS = 0x00;
+    private static final int ENUM_KLASS = 0x01;
+
+    protected static class Edge {
+        final int from;
+        final char fromIndex;
+        final int to;
+        final char toIndex;
+        final String label;
+
+        public Edge(int from, char fromIndex, int to, char toIndex, String label) {
+            this.from = from;
+            this.fromIndex = fromIndex;
+            this.to = to;
+            this.toIndex = toIndex;
+            this.label = label;
+        }
+
+        @Override
+        public int hashCode() {
+            int h = from ^ to;
+            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 == other.from
+                        && fromIndex == other.fromIndex
+                        && to == other.to
+                        && toIndex == other.toIndex
+                        && (label == other.label || (label != null && label.equals(other.label)));
+            }
+            return false;
+        }
+    }
+
+    private static final class CosntantPool extends LinkedHashMap<Object, Integer> {
+        private final LinkedList<Integer> availableIds;
+        private int nextId;
+        private static final long serialVersionUID = -2676889957907285681L;
+        public CosntantPool() {
+            super(50, 0.65f);
+            availableIds = new LinkedList<>();
+        }
+        @Override
+        protected boolean removeEldestEntry(java.util.Map.Entry<Object, Integer> eldest) {
+            if (size() > CONSTANT_POOL_MAX_SIZE) {
+                availableIds.addFirst(eldest.getValue());
+                return true;
+            }
+            return false;
+        }
+
+        private Integer nextAvailableId() {
+            if (!availableIds.isEmpty()) {
+                return availableIds.removeFirst();
+            }
+            return nextId++;
+        }
+
+        public int add(Object obj) {
+            Integer id = nextAvailableId();
+            put(obj, id);
+            return id;
+        }
+    }
+
+    private final CosntantPool constantPool;
+
+
+    private final ByteBuffer buffer;
+    private final WritableByteChannel channel;
+
+
+    public BinaryGraphPrinter(WritableByteChannel channel) {
+        constantPool = new CosntantPool();
+        buffer = ByteBuffer.allocateDirect(64 * 1024);
+        this.channel = channel;
+    }
+
+    public void print(Graph graph, String title, SchedulePhase predefinedSchedule) throws IOException {
+        Set<Node> noBlockNodes = new HashSet<>();
+        SchedulePhase schedule = predefinedSchedule;
+        if (schedule == null) {
+            try {
+                schedule = new SchedulePhase();
+                schedule.apply((StructuredGraph) graph);
+            } catch (Throwable t) {
+            }
+        }
+        ControlFlowGraph cfg =  schedule == null ? null : schedule.getCFG();
+
+        BlockMap<List<ScheduledNode>> blockToNodes = schedule == null ? null : schedule.getBlockToNodesMap();
+        writeByte(BEGIN_GRAPH);
+        writePoolObject(title);
+        int edgeCount = writeNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes);
+        writeEdges(graph, edgeCount);
+
+
+        Block[] blocks = cfg == null ? null : cfg.getBlocks();
+        writeBlocks(blocks, noBlockNodes, blockToNodes);
+        flush();
+    }
+
+    private void flush() throws IOException {
+        buffer.flip();
+        channel.write(buffer);
+        buffer.compact();
+    }
+
+    private void ensureAvailable(int i) throws IOException {
+        while (buffer.remaining() < i) {
+            flush();
+        }
+    }
+
+    private void writeByte(int b) throws IOException {
+        ensureAvailable(1);
+        buffer.put((byte) b);
+    }
+
+    private void writeInt(int b) throws IOException {
+        ensureAvailable(4);
+        buffer.putInt(b);
+    }
+
+    private void writeLong(long b) throws IOException {
+        ensureAvailable(8);
+        buffer.putLong(b);
+    }
+
+    private void writeDouble(double b) throws IOException {
+        ensureAvailable(8);
+        buffer.putDouble(b);
+    }
+
+    private void writeFloat(float b) throws IOException {
+        ensureAvailable(4);
+        buffer.putFloat(b);
+    }
+
+    private void writeShort(char b) throws IOException {
+        ensureAvailable(2);
+        buffer.putChar(b);
+    }
+
+    private void writeString(String str) throws IOException {
+        writeInt(str.length());
+        ensureAvailable(str.length() * 2);
+        for (int i = 0; i < str.length(); i++) {
+            buffer.putChar(str.charAt(i));
+        }
+    }
+
+    private void writeBytes(byte[] b) throws IOException {
+        if (b == null) {
+            writeInt(-1);
+        } else {
+            writeInt(b.length);
+            ensureAvailable(b.length);
+            buffer.put(b);
+        }
+    }
+
+    private void writeInts(int[] b) throws IOException {
+        if (b == null) {
+            writeInt(-1);
+        } else {
+            writeInt(b.length);
+            ensureAvailable(b.length * 4);
+            for (int i = 0; i < b.length; i++) {
+                buffer.putInt(b[i]);
+            }
+        }
+    }
+
+    private void writeDoubles(double[] b) throws IOException {
+        if (b == null) {
+            writeInt(-1);
+        } else {
+            writeInt(b.length);
+            ensureAvailable(b.length * 8);
+            for (int i = 0; i < b.length; i++) {
+                buffer.putDouble(b[i]);
+            }
+        }
+    }
+
+    private void writePoolObject(Object object) throws IOException {
+        if (object == null) {
+            writeByte(POOL_NULL);
+            return;
+        }
+        Integer id = constantPool.get(object);
+        if (id == null) {
+            addPoolEntry(object);
+        } else {
+            if (object instanceof Enum<?>) {
+                writeByte(POOL_ENUM);
+            } else if (object instanceof Class<?>) {
+                writeByte(POOL_CLASS);
+            } else if (object instanceof ResolvedJavaMethod) {
+                writeByte(POOL_METHOD);
+            } else {
+                writeByte(POOL_STRING);
+            }
+            writeInt(id.intValue());
+        }
+    }
+
+    private void addPoolEntry(Object object) throws IOException {
+        int index = constantPool.add(object);
+        writeByte(POOL_NEW);
+        writeInt(index);
+        if (object instanceof Class<?>) {
+            Class<?> klass = (Class< ? >) object;
+            writeByte(POOL_CLASS);
+            writePoolObject(klass.getName());
+            if (klass.isEnum()) {
+                writeByte(ENUM_KLASS);
+                Object[] enumConstants = object.getClass().getEnumConstants();
+                writeInt(enumConstants.length);
+                for (Object o : enumConstants) {
+                    writePoolObject(((Enum<?>) o).name());
+                }
+            } else {
+                writePoolObject(klass.getName());
+                writeByte(KLASS);
+            }
+        } else if (object instanceof Enum<?>) {
+            writeByte(POOL_ENUM);
+            writePoolObject(object.getClass());
+            writeInt(((Enum) object).ordinal());
+        } else if (object instanceof ResolvedJavaMethod) {
+            writeByte(POOL_METHOD);
+            writeBytes(((ResolvedJavaMethod) object).code());
+        } else {
+            writeByte(POOL_STRING);
+            writeString(object.toString());
+        }
+    }
+
+    private void writePropertyObject(Object obj) throws IOException {
+        if (obj instanceof Integer) {
+            writeByte(PROPERTY_INT);
+            writeInt(((Integer) obj).intValue());
+        } else if (obj instanceof Long) {
+            writeByte(PROPERTY_LONG);
+            writeLong(((Long) obj).longValue());
+        } else if (obj instanceof Double) {
+            writeByte(PROPERTY_DOUBLE);
+            writeDouble(((Double) obj).doubleValue());
+        } else if (obj instanceof Float) {
+            writeByte(PROPERTY_FLOAT);
+            writeFloat(((Float) obj).floatValue());
+        } else if (obj instanceof Boolean) {
+            if (((Boolean) obj).booleanValue()) {
+                writeByte(PROPERTY_TRUE);
+            } else {
+                writeByte(PROPERTY_FALSE);
+            }
+        } else if (obj.getClass().isArray()) {
+            Class< ? > componentType = obj.getClass().getComponentType();
+            if (componentType.isPrimitive()) {
+                if (componentType == Double.TYPE) {
+                    writeByte(PROPERTY_ARRAY);
+                    writeByte(PROPERTY_DOUBLE);
+                    writeDoubles((double[]) obj);
+                } else if (componentType == Integer.TYPE) {
+                    writeByte(PROPERTY_ARRAY);
+                    writeByte(PROPERTY_DOUBLE);
+                    writeInts((int[]) obj);
+                } else {
+                    writeByte(PROPERTY_POOL);
+                    writePoolObject(obj);
+                }
+            } else {
+                writeByte(PROPERTY_ARRAY);
+                writeByte(PROPERTY_POOL);
+                Object[] array = (Object[]) obj;
+                writeInt(array.length);
+                for (Object o : array) {
+                    writePoolObject(o);
+                }
+            }
+        } else {
+            writeByte(PROPERTY_POOL);
+            writePoolObject(obj);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private int writeNodes(Graph graph, NodeMap<Block> nodeToBlock, Set<Node> noBlockNodes) throws IOException {
+        int edges = 0;
+        Map<Object, Object> props = new HashMap<>();
+        writeInt(graph.getNodeCount());
+        for (Node node : graph.getNodes()) {
+            node.getNodeClass().getDebugProperties(node, props);
+            String name = node.toString(Verbosity.Name);
+
+            writeInt(node.getId());
+            writePoolObject(name);
+            writePoolObject(node.getClass().getSimpleName());
+            Block block = nodeToBlock == null ? null : nodeToBlock.get(node);
+            if (block != null) {
+                writeInt(block.getId());
+            } else {
+                writeInt(-1);
+                noBlockNodes.add(node);
+            }
+            writeByte(node.predecessor() != null ? 1 : 0);
+            writeInt(props.size());
+            for (Entry<Object, Object> entry : props.entrySet()) {
+                String key = entry.getKey().toString();
+                String value = entry.getValue() == null ? "null" : entry.getValue().toString();
+                writePoolObject(key);
+                writePropertyObject(value);
+            }
+            edges += node.successors()/*.nonNull()*/.count();
+            edges += node.inputs()/*.nonNull()*/.count();
+            props.clear();
+        }
+
+        return edges;
+    }
+
+    @SuppressWarnings("deprecation")
+    private void writeEdges(Graph graph, int edgeCount) throws IOException {
+        writeInt(edgeCount);
+        for (Node node : graph.getNodes()) {
+            // successors
+            char fromIndex = 0;
+            NodeClassIterator succIter = node.successors().iterator();
+            while (succIter.hasNext()) {
+                Position position = succIter.nextPosition();
+                Node successor = node.getNodeClass().get(node, position);
+                if (successor != null) {
+                    writeShort(fromIndex);
+                    writeInt(node.getId());
+                    writeShort((char) 0);
+                    writeInt(successor.getId());
+                    writePoolObject(node.getNodeClass().getName(position));
+                }
+                fromIndex++;
+            }
+
+            // inputs
+            char toIndex = 1;
+            NodeClassIterator inputIter = node.inputs().iterator();
+            while (inputIter.hasNext()) {
+                Position position = inputIter.nextPosition();
+                Node input = node.getNodeClass().get(node, position);
+                if (input != null) {
+                    writeShort((char) input.successors().count());
+                    writeInt(input.getId());
+                    writeShort(toIndex);
+                    writeInt(node.getId());
+                    writePoolObject(node.getNodeClass().getName(position));
+                }
+                toIndex++;
+            }
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    private void writeBlocks(Block[] blocks, Set<Node> noBlockNodes, BlockMap<List<ScheduledNode>> blockToNodes) throws IOException {
+        if (blocks != null) {
+            writeInt(blocks.length + (noBlockNodes.isEmpty() ? 0 : 1));
+            int suxCount = 0;
+            for (Block block : blocks) {
+                List<ScheduledNode> nodes = blockToNodes.get(block);
+                writeInt(block.getId());
+                writeInt(nodes.size());
+                for (Node node : nodes) {
+                    writeInt(node.getId());
+                }
+                suxCount += block.getSuccessors().size();
+            }
+            if (!noBlockNodes.isEmpty()) {
+                writeInt(-1);
+                writeInt(noBlockNodes.size());
+                for (Node node : noBlockNodes) {
+                    writeInt(node.getId());
+                }
+            }
+            writeInt(suxCount);
+            for (Block block : blocks) {
+                for (Block sux : block.getSuccessors()) {
+                    writeInt(block.getId());
+                    writeInt(sux.getId());
+                }
+            }
+        } else {
+            writeInt(0);
+        }
+    }
+
+    public void beginGroup(String name, String shortName, ResolvedJavaMethod method, int bci) throws IOException {
+        writeByte(BEGIN_GROUP);
+        writePoolObject(name);
+        writePoolObject(shortName);
+        writePoolObject(method);
+        writeInt(bci);
+    }
+
+    public void endGroup() throws IOException {
+        writeByte(CLOSE_GROUP);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinterDumpHandler.java	Mon Jul 09 14:15:55 2012 +0200
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.printer;
+
+import java.io.*;
+import java.net.*;
+import java.nio.channels.*;
+import java.util.*;
+
+import com.oracle.max.criutils.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.debug.*;
+import com.oracle.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 BinaryGraphPrinterDumpHandler implements DebugDumpHandler {
+
+    private static final String DEFAULT_FILE_NAME = "output.gvb";
+
+    private BinaryGraphPrinter printer;
+    private List<String> previousInlineContext = new ArrayList<>();
+    private String fileName;
+    private String host;
+    private int port;
+    private int failuresCount;
+
+    /**
+     * Creates a new {@link BinaryGraphPrinterDumpHandler} that writes output to a file named after the compiled method.
+     */
+    public BinaryGraphPrinterDumpHandler() {
+        this.fileName = DEFAULT_FILE_NAME;
+    }
+
+    /**
+     * Creates a new {@link BinaryGraphPrinterDumpHandler} that sends output to a remote IdealGraphVisualizer instance.
+     */
+    public BinaryGraphPrinterDumpHandler(String host, int port) {
+        this.host = host;
+        this.port = port;
+    }
+
+    private void ensureInitialized() {
+        if (printer == null) {
+            if (failuresCount > 8) {
+                return;
+            }
+            previousInlineContext.clear();
+            if (fileName != null) {
+                initializeFilePrinter();
+            } else {
+                initializeNetworkPrinter();
+            }
+        }
+    }
+
+    private void initializeFilePrinter() {
+        try {
+            printer = new BinaryGraphPrinter(FileChannel.open(new File(fileName).toPath()));
+        } catch (IOException e) {
+            failuresCount++;
+            printer = null;
+        }
+    }
+
+    private void initializeNetworkPrinter() {
+        try {
+            SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port));
+            printer = new BinaryGraphPrinter(channel);
+            TTY.println("Connected to the IGV on port %d", port);
+        } catch (IOException e) {
+            TTY.println("Could not connect to the IGV on port %d: %s", port, e);
+            failuresCount++;
+            printer = null;
+        }
+    }
+
+    @Override
+    public void dump(Object object, final String message) {
+        if (object instanceof Graph) {
+            ensureInitialized();
+            if (printer == null) {
+                return;
+            }
+            final Graph graph = (Graph) object;
+
+            if (printer != null) {
+                // Get all current RiResolvedMethod instances in the context.
+                List<String> inlineContext = getInlineContext();
+
+                // Reverse list such that inner method comes after outer method.
+                Collections.reverse(inlineContext);
+
+                // Check for method scopes that must be closed since the previous dump.
+                for (int i = 0; i < previousInlineContext.size(); ++i) {
+                    if (i >= inlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
+                        for (int j = previousInlineContext.size() - 1; j >= i; --j) {
+                            closeScope();
+                        }
+                        break;
+                    }
+                }
+
+                // Check for method scopes that must be opened since the previous dump.
+                for (int i = 0; i < inlineContext.size(); ++i) {
+                    if (i >= previousInlineContext.size() || !inlineContext.get(i).equals(previousInlineContext.get(i))) {
+                        for (int j = i; j < inlineContext.size(); ++j) {
+                            openScope(inlineContext.get(j), j == 0);
+                        }
+                        break;
+                    }
+                }
+
+                // Save inline context for next dump.
+                previousInlineContext = inlineContext;
+
+                Debug.sandbox("PrintingGraph", new Runnable() {
+
+                    @Override
+                    public void run() {
+                        // Finally, output the graph.
+                        try {
+                            printer.print(graph, message, null);
+                        } catch (IOException e) {
+                            failuresCount++;
+                            printer = null;
+                        }
+                    }
+                });
+            }
+        }
+    }
+
+    private static List<String> getInlineContext() {
+        List<String> result = new ArrayList<>();
+        for (Object o : Debug.context()) {
+            if (o instanceof ResolvedJavaMethod) {
+                ResolvedJavaMethod method = (ResolvedJavaMethod) o;
+                result.add(MetaUtil.format("%H::%n(%p)", method));
+            } else if (o instanceof DebugDumpScope) {
+                DebugDumpScope debugDumpScope = (DebugDumpScope) o;
+                if (debugDumpScope.decorator && !result.isEmpty()) {
+                    result.set(result.size() - 1, debugDumpScope.name + ":" + result.get(result.size() - 1));
+                } else {
+                    result.add(debugDumpScope.name);
+                }
+            }
+        }
+        return result;
+    }
+
+    private void openScope(String name, boolean showThread) {
+        String prefix = showThread ? Thread.currentThread().getName() + ":" : "";
+        try {
+            printer.beginGroup(prefix + name, name, Debug.contextLookup(ResolvedJavaMethod.class), -1);
+        } catch (IOException e) {
+            failuresCount++;
+            printer = null;
+        }
+    }
+
+    private void closeScope() {
+        try {
+            printer.endGroup();
+        } catch (IOException e) {
+            failuresCount++;
+            printer = null;
+        }
+    }
+}
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Mon Jul 09 14:15:55 2012 +0200
@@ -94,12 +94,12 @@
                 schedule = new SchedulePhase();
                 schedule.apply((StructuredGraph) graph);
             } catch (Throwable t) {
-                schedule = null;
             }
         }
+        ControlFlowGraph cfg =  schedule == null ? null : schedule.getCFG();
 
         beginNodes();
-        List<Edge> edges = printNodes(graph, schedule == null ? null : schedule.getCFG().getNodeToBlock(), noBlockNodes);
+        List<Edge> edges = printNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes);
         endNodes();
 
         beginEdges();
@@ -108,10 +108,10 @@
         }
         endEdges();
 
-        if (schedule != null) {
+        if (cfg != null && cfg.getBlocks() != null) {
             beginControlFlow();
-            for (Block block : schedule.getCFG().getBlocks()) {
-                printBlock(graph, block, schedule.getCFG().getNodeToBlock());
+            for (Block block : cfg.getBlocks()) {
+                printBlock(graph, block, cfg.getNodeToBlock());
             }
             printNoBlock(noBlockNodes);
             endControlFlow();
--- a/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java	Mon Jul 09 14:15:55 2012 +0200
@@ -23,6 +23,7 @@
  */
 package com.sun.hotspot.igv.coordinator;
 
+import com.sun.hotspot.igv.connection.BinaryServer;
 import com.sun.hotspot.igv.connection.Server;
 import com.sun.hotspot.igv.coordinator.actions.*;
 import com.sun.hotspot.igv.data.GraphDocument;
@@ -61,6 +62,7 @@
     private GraphDocument document;
     private FolderNode root;
     private Server server;
+    private BinaryServer binaryServer;
 
     private OutlineTopComponent() {
         initComponents();
@@ -116,6 +118,7 @@
         };
         
         server = new Server(callback);
+        binaryServer = new BinaryServer(callback);
     }
 
     public void clear() {
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java	Mon Jul 09 14:15:55 2012 +0200
@@ -243,10 +243,7 @@
     }
 
     public void addEdge(InputEdge c) {
-        // Be tolerant with duplicated edges.
-        if (!edges.contains(c)) {
-            edges.add(c);
-        }
+        edges.add(c);
     }
 
     public Group getGroup() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Mon Jul 09 14:15:55 2012 +0200
@@ -0,0 +1,447 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.sun.hotspot.igv.data.serialization;
+
+import com.sun.hotspot.igv.data.*;
+import com.sun.hotspot.igv.data.services.GroupCallback;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.List;
+import javax.swing.SwingUtilities;
+
+/**
+ *
+ * @author gd
+ */
+public class BinaryParser {
+    private static final int BEGIN_GROUP = 0x00;
+    private static final int BEGIN_GRAPH = 0x01;
+    private static final int CLOSE_GROUP = 0x02;
+
+    private static final int POOL_NULL = -1;
+    private static final int POOL_NEW = 0x00;
+    private static final int POOL_STRING = 0x01;
+    private static final int POOL_ENUM = 0x02;
+    private static final int POOL_CLASS = 0x03;
+    private static final int POOL_METHOD = 0x04;
+    
+    private static final int KLASS = 0x00;
+    private static final int ENUM_KLASS = 0x01;
+    
+    private static final int PROPERTY_POOL = 0x00;
+    private static final int PROPERTY_INT = 0x01;
+    private static final int PROPERTY_LONG = 0x02;
+    private static final int PROPERTY_DOUBLE = 0x03;
+    private static final int PROPERTY_FLOAT = 0x04;
+    private static final int PROPERTY_TRUE = 0x05;
+    private static final int PROPERTY_FALSE = 0x06;
+    private static final int PROPERTY_ARRAY = 0x07;
+    
+    private static final String NO_BLOCK = "noBlock";
+    
+    private GroupCallback callback;
+    private List<Object> constantPool;
+    private int maxConstant;
+    private final ByteBuffer buffer;
+    private final ReadableByteChannel channel;
+    private Deque<Folder> folderStack;
+    
+    private static class Klass {
+        public String name;
+        public Klass(String name) {
+            this.name = name;
+        }
+    }
+    
+    private static class EnumKlass extends Klass {
+        public String[] values;
+        public EnumKlass(String name, String[] values) {
+            super(name);
+            this.values = values;
+        }
+    }
+    
+    private static class EnumValue {
+        public EnumKlass enumKlass;
+        public int ordinal;
+        public EnumValue(EnumKlass enumKlass, int ordinal) {
+            this.enumKlass = enumKlass;
+            this.ordinal = ordinal;
+        }
+    }
+
+    public BinaryParser(GroupCallback callback, ReadableByteChannel channel) {
+        this.callback = callback;
+        constantPool = new ArrayList<>();
+        buffer = ByteBuffer.allocateDirect(64 * 1024);
+        buffer.flip();
+        this.channel = channel;
+        folderStack = new LinkedList<>();
+    }
+    
+    private void fill() throws IOException {
+        buffer.compact();
+        channel.read(buffer);
+        buffer.flip();
+    }
+    
+    private void ensureAvailable(int i) throws IOException {
+        while (buffer.remaining() < i) {
+            fill();
+        }
+    }
+    
+    private int readByte() throws IOException {
+        ensureAvailable(1);
+        return ((int)buffer.get()) & 0xff;
+    }
+
+    private int readInt() throws IOException {
+        ensureAvailable(4);
+        return buffer.getInt();
+    }
+    
+    private char readShort() throws IOException {
+        ensureAvailable(2);
+        return buffer.getChar();
+    }
+    
+    private long readLong() throws IOException {
+        ensureAvailable(8);
+        return buffer.getLong();
+    }
+    
+    private double readDouble() throws IOException {
+        ensureAvailable(8);
+        return buffer.getDouble();
+    }
+    
+    private float readFloat() throws IOException {
+        ensureAvailable(4);
+        return buffer.getFloat();
+    }
+
+    private String readString() throws IOException {
+        int len = readInt();
+        ensureAvailable(len * 2);
+        char[] chars = new char[len];
+        for (int i = 0; i < len; i++) {
+            chars[i] = buffer.getChar();
+        }
+        return new String(chars);
+    }
+
+    private byte[] readBytes() throws IOException {
+        int len = readInt();
+        if (len < 0) {
+            return null;
+        }
+        ensureAvailable(len);
+        byte[] data = new byte[len];
+        buffer.get(data);
+        return data;
+    }
+    
+    private String readIntsToString() throws IOException {
+        int len = readInt();
+        if (len < 0) {
+            return "null";
+        }
+        ensureAvailable(len * 4);
+        StringBuilder sb = new StringBuilder().append('[');
+        for (int i = 0; i < len; i++) {
+            sb.append(buffer.getInt());
+            if (i < len - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+    
+    private String readDoublesToString() throws IOException {
+        int len = readInt();
+        if (len < 0) {
+            return "null";
+        }
+        ensureAvailable(len * 8);
+        StringBuilder sb = new StringBuilder().append('[');
+        for (int i = 0; i < len; i++) {
+            sb.append(buffer.getDouble());
+            if (i < len - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+    
+    private String readPoolObjectsToString() throws IOException {
+        int len = readInt();
+        if (len < 0) {
+            return "null";
+        }
+        StringBuilder sb = new StringBuilder().append('[');
+        for (int i = 0; i < len; i++) {
+            sb.append(readPoolObject(Object.class));
+            if (i < len - 1) {
+                sb.append(", ");
+            }
+        }
+        sb.append(']');
+        return sb.toString();
+    }
+    
+    private <T> T readPoolObject(Class<T> klass) throws IOException {
+        int type = readByte();
+        if (type == POOL_NULL) {
+            return null;
+        }
+        if (type == POOL_NEW) {
+            return (T) addPoolEntry(klass);
+        }
+        int index = readInt();
+        if (index < 0 || index >= constantPool.size()) {
+            throw new IOException("Invalid constant pool index : " + index);
+        }
+        Object obj = constantPool.get(index);
+        return (T) obj;
+    }
+    
+    private boolean assertObjectType(Class<?> klass, int type) {
+        switch(type) {
+            case POOL_CLASS:
+                return klass.isAssignableFrom(Klass.class);
+            case POOL_ENUM:
+                return klass.isAssignableFrom(EnumValue.class);
+            case POOL_METHOD:
+                return klass.isAssignableFrom(byte[].class);
+            case POOL_STRING:
+                return klass.isAssignableFrom(String.class);
+            case POOL_NULL:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private Object addPoolEntry(Class<?> klass) throws IOException {
+        int index = readInt();
+        int type = readByte();
+        assert assertObjectType(klass, type) : "Wrong object type : " + klass + " != " + type;
+        Object obj;
+        switch(type) {
+            case POOL_CLASS:
+                String name = readString();
+                int klasstype = readByte();
+                if (klasstype == ENUM_KLASS) {
+                    int len = readInt();
+                    String[] values = new String[len];
+                    for (int i = 0; i < len; i++) {
+                        values[i] = readPoolObject(String.class);
+                    }
+                    obj = new EnumKlass(name, values);
+                } else if (klasstype == KLASS) {
+                    obj = new Klass(name);
+                } else {
+                    throw new IOException("unknown klass type");
+                }
+                break;
+            case POOL_ENUM:
+                EnumKlass enumClass = readPoolObject(EnumKlass.class);
+                int ordinal = readInt();
+                obj = new EnumValue(enumClass, ordinal);
+                break;
+            case POOL_METHOD:
+                obj = readBytes();
+                break;
+            case POOL_STRING:
+                obj = readString();
+                break;
+            default:
+                throw new IOException("unknown pool type");
+        }
+        while (constantPool.size() <= index) {
+            constantPool.add(null);
+        }
+        constantPool.set(index, obj);
+        return obj;
+    }
+    
+    private Object readPropertyObject() throws IOException {
+        int type = readByte();
+        switch (type) {
+            case PROPERTY_INT:
+                return readInt();
+            case PROPERTY_LONG:
+                return readLong();
+            case PROPERTY_FLOAT:
+                return readFloat();
+            case PROPERTY_DOUBLE:
+                return readDouble();
+            case PROPERTY_TRUE:
+                return Boolean.TRUE;
+            case PROPERTY_FALSE:
+                return Boolean.FALSE;
+            case PROPERTY_POOL:
+                return readPoolObject(Object.class);
+            case PROPERTY_ARRAY:
+                int subType = readByte();
+                switch(subType) {
+                    case PROPERTY_INT:
+                        return readIntsToString();
+                    case PROPERTY_DOUBLE:
+                        return readDoublesToString();
+                    case PROPERTY_POOL:
+                        return readPoolObjectsToString();
+                    default:
+                        throw new IOException("Unknown type");
+                }
+            default:
+                throw new IOException("Unknown type");
+        }
+    }
+
+    public void parse() throws IOException {
+        folderStack.push(new GraphDocument());
+        while(true) {
+            parseRoot();
+        }
+    }
+
+    private void parseRoot() throws IOException {
+        int type = readByte();
+        switch(type) {
+            case BEGIN_GRAPH: {
+                final Folder parent = folderStack.peek();
+                final InputGraph graph = parseGraph();
+                SwingUtilities.invokeLater(new Runnable(){
+                    @Override
+                    public void run() {
+                        parent.addElement(graph);
+                    }
+                });
+                break;
+            }
+            case BEGIN_GROUP: {
+                final Folder parent = folderStack.peek();
+                final Group group = parseGroup(parent);
+                if (callback == null || parent instanceof Group) {
+                    SwingUtilities.invokeLater(new Runnable(){
+                        @Override
+                        public void run() {
+                            parent.addElement(group);
+                        }
+                    });
+                }
+                folderStack.push(group);
+                if (callback != null && parent instanceof GraphDocument) {
+                    callback.started(group);
+                }
+                break;
+            }
+            case CLOSE_GROUP: {
+                if (folderStack.isEmpty()) {
+                    throw new IOException("Unbalanced groups");
+                }
+                folderStack.pop();
+                break;
+            }
+            default:
+                throw new IOException("unknown root : " + type);
+        }
+    }
+
+    private Group parseGroup(Folder parent) throws IOException {
+        String name = readPoolObject(String.class);
+        String shortName = readPoolObject(String.class);
+        byte[] bytecodes = readPoolObject(byte[].class);
+        int bci = readInt();
+        Group group = new Group(parent);
+        group.getProperties().setProperty("name", name);
+        final InputMethod method = new InputMethod(group, name, shortName, bci);
+        if (bytecodes != null) {
+            method.setBytecodes("TODO");
+        }
+        group.setMethod(method);
+        return group;
+    }
+    
+    private InputGraph parseGraph() throws IOException {
+        String title = readPoolObject(String.class);
+        InputGraph graph = new InputGraph(title);
+        parseNodes(graph);
+        parseEdges(graph);
+        parseBlocks(graph);
+        graph.ensureNodesInBlocks();
+        return graph;
+    }
+    
+    private void parseBlocks(InputGraph graph) throws IOException {
+        int blockCount = readInt();
+        for (int i = 0; i < blockCount; i++) {
+            int id = readInt();
+            String name = id >= 0 ? Integer.toString(id) : NO_BLOCK;
+            InputBlock block = graph.addBlock(name);
+            int nodeCount = readInt();
+            for (int j = 0; j < nodeCount; j++) {
+                block.addNode(readInt());
+            }
+        }
+        int edgeCount = readInt();
+        for (int i = 0; i < edgeCount; i++) {
+            int from = readInt();
+            int to = readInt();
+            String fromName = from >= 0 ? Integer.toString(from) : NO_BLOCK;
+            String toName = to >= 0 ? Integer.toString(to) : NO_BLOCK;
+            graph.addBlockEdge(graph.getBlock(fromName), graph.getBlock(toName));
+        }
+    }
+    
+    private void parseEdges(InputGraph graph) throws IOException {
+        int count = readInt();
+        for (int i = 0; i < count; i++) {
+            char fromIndex = readShort();
+            int from = readInt();
+            char toIndex = readShort();
+            int to = readInt();
+            String label = readPoolObject(String.class);
+            graph.addEdge(new InputEdge(fromIndex, toIndex, from, to, label));
+        }
+    }
+
+    private void parseNodes(InputGraph graph) throws IOException {
+        int count = readInt();
+        
+        for (int i = 0; i < count; i++) {
+            int id = readInt();
+            InputNode node = new InputNode(id);
+            final Properties properties = node.getProperties();
+            String name = readPoolObject(String.class);
+            String simpleName = readPoolObject(String.class);
+            int block = readInt();
+            int preds = readByte();
+            properties.setProperty("name", name);
+            properties.setProperty("class", simpleName);
+            properties.setProperty("predecessorCount", Integer.toString(preds));
+            if (block > 0) {
+                properties.setProperty("block", Integer.toString(block));
+            } else {
+                properties.setProperty("block", NO_BLOCK);
+            }
+            int propCount = readInt();
+            for (int j = 0; j < propCount; j++) {
+                String key = readPoolObject(String.class);
+                Object value = readPropertyObject();
+                properties.setProperty(key, value.toString());
+            }
+            graph.addNode(node);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryClient.java	Mon Jul 09 14:15:55 2012 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1998, 2007, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.hotspot.igv.connection;
+
+import com.sun.hotspot.igv.data.serialization.BinaryParser;
+import com.sun.hotspot.igv.data.services.GroupCallback;
+import java.io.IOException;
+import java.nio.channels.SocketChannel;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author Thomas Wuerthinger
+ */
+public class BinaryClient implements Runnable {
+
+    private SocketChannel socket;
+    private GroupCallback callback;
+
+    public BinaryClient(SocketChannel socket, GroupCallback callback) {
+        this.callback = callback;
+        this.socket = socket;
+    }
+
+    @Override
+    public void run() {
+
+        try {
+            final SocketChannel channel = socket;
+            channel.configureBlocking(true);
+            new BinaryParser(callback, channel).parse();
+        } catch (IOException ex) {
+            Exceptions.printStackTrace(ex);
+        } finally {
+            try {
+                socket.close();
+            } catch (IOException ex) {
+                Exceptions.printStackTrace(ex);
+            }
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/NetworkConnection/src/com/sun/hotspot/igv/connection/BinaryServer.java	Mon Jul 09 14:15:55 2012 +0200
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1998, 2007, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.hotspot.igv.connection;
+
+import com.sun.hotspot.igv.data.services.GroupCallback;
+import com.sun.hotspot.igv.settings.Settings;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.util.RequestProcessor;
+
+/**
+ *
+ * @author Thomas Wuerthinger
+ */
+public class BinaryServer implements PreferenceChangeListener {
+
+    private ServerSocketChannel serverSocket;
+    private GroupCallback callback;
+    private int port;
+    private Runnable serverRunnable;
+
+    public BinaryServer(GroupCallback callback) {
+
+        this.callback = callback;
+        initializeNetwork();
+        Settings.get().addPreferenceChangeListener(this);
+    }
+
+    @Override
+    public void preferenceChange(PreferenceChangeEvent e) {
+
+        int curPort = Integer.parseInt(Settings.get().get(Settings.PORT_BINARY, Settings.PORT_BINARY_DEFAULT));
+        if (curPort != port) {
+            initializeNetwork();
+        }
+    }
+
+    private void initializeNetwork() {
+
+        int curPort = Integer.parseInt(Settings.get().get(Settings.PORT_BINARY, Settings.PORT_BINARY_DEFAULT));
+        this.port = curPort;
+        try {
+            serverSocket = ServerSocketChannel.open();
+            serverSocket.bind(new InetSocketAddress(curPort));
+        } catch (IOException ex) {
+            NotifyDescriptor message = new NotifyDescriptor.Message("Could not create server. Listening for incoming binary data is disabled.", NotifyDescriptor.ERROR_MESSAGE);
+            DialogDisplayer.getDefault().notifyLater(message);
+            return;
+        }
+
+        Runnable runnable = new Runnable() {
+
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        SocketChannel clientSocket = serverSocket.accept();
+                        if (serverRunnable != this) {
+                            clientSocket.close();
+                            return;
+                        }
+                        RequestProcessor.getDefault().post(new BinaryClient(clientSocket, callback), 0, Thread.MAX_PRIORITY);
+                    } catch (IOException ex) {
+                        serverSocket = null;
+                        NotifyDescriptor message = new NotifyDescriptor.Message("Error during listening for incoming connections. Listening for incoming binary data is disabled.", NotifyDescriptor.ERROR_MESSAGE);
+                        DialogDisplayer.getDefault().notifyLater(message);
+                        return;
+                    }
+                }
+            }
+        };
+
+        serverRunnable = runnable;
+
+        RequestProcessor.getDefault().post(runnable, 0, Thread.MAX_PRIORITY);
+    }
+}
--- a/src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java	Wed Jul 04 15:27:28 2012 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java	Mon Jul 09 14:15:55 2012 +0200
@@ -37,7 +37,9 @@
     public final static String NODE_WIDTH = "nodeWidth";
     public final static String NODE_WIDTH_DEFAULT = "100";
     public final static String PORT = "port";
+    public final static String PORT_BINARY = "portBinary";
     public final static String PORT_DEFAULT = "4444";
+    public final static String PORT_BINARY_DEFAULT = "4445";
     public final static String DIRECTORY = "directory";
     public final static String DIRECTORY_DEFAULT = System.getProperty("user.dir");