changeset 5811:6a725f3c4bb0

Merge
author Gilles Duboscq <duboscq@ssw.jku.at>
date Mon, 09 Jul 2012 14:22:22 +0200
parents 506e76281145 (current diff) bc237d8b6f99 (diff)
children 32613b375b30
files graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java
diffstat 24 files changed, 1401 insertions(+), 66 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalOptions.java	Mon Jul 09 14:22:22 2012 +0200
@@ -137,11 +137,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                         = ____;
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/graph/PostOrderNodeIterator.java	Mon Jul 09 14:22:22 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.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/CanonicalizerPhase.java	Mon Jul 09 14:22:22 2012 +0200
@@ -22,6 +22,9 @@
  */
 package com.oracle.graal.compiler.phases;
 
+import java.util.*;
+import java.util.concurrent.*;
+
 import com.oracle.graal.api.code.*;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.debug.*;
@@ -51,6 +54,7 @@
 
     private NodeWorkList workList;
     private Tool tool;
+    private List<Node> snapshotTemp;
 
     public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
         this(target, runtime, assumptions, null, 0, null);
@@ -82,6 +86,7 @@
         this.runtime = runtime;
         this.immutabilityPredicate = immutabilityPredicate;
         this.initWorkingSet = workingSet;
+        this.snapshotTemp = new ArrayList<>();
     }
 
     @Override
@@ -97,14 +102,6 @@
         }
         tool = new Tool(workList, runtime, target, assumptions, immutabilityPredicate);
         processWorkSet(graph);
-
-        while (graph.getUsagesDroppedNodesCount() > 0) {
-            for (Node n : graph.getAndCleanUsagesDroppedNodes()) {
-                if (!n.isDeleted() && n.usages().size() == 0 && GraphUtil.isFloatingNode().apply(n)) {
-                    n.safeDelete();
-                }
-            }
-        }
     }
 
     public interface IsImmutablePredicate {
@@ -138,8 +135,19 @@
                 return;
             }
             int mark = graph.getMark();
-            tryCanonicalize(node, graph, tool);
-            tryInferStamp(node, graph);
+            if (!tryKillUnused(node)) {
+                node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
+                if (!tryCanonicalize(node, graph, tool)) {
+                    tryInferStamp(node, graph);
+                } else {
+                    for (Node in : snapshotTemp) {
+                        if (in.isAlive() && in.usages().isEmpty()) {
+                            GraphUtil.killWithUnusedFloatingInputs(in);
+                        }
+                    }
+                }
+                snapshotTemp.clear();
+            }
 
             for (Node newNode : graph.getNewNodes(mark)) {
                 workList.add(newNode);
@@ -147,6 +155,14 @@
         }
     }
 
+    private static boolean tryKillUnused(Node node) {
+        if (node.isAlive() && GraphUtil.isFloatingNode().apply(node) && node.usages().isEmpty()) {
+            GraphUtil.killWithUnusedFloatingInputs(node);
+            return true;
+        }
+        return false;
+    }
+
     public static boolean tryGlobalValueNumbering(Node node, StructuredGraph graph) {
         if (node.getNodeClass().valueNumberable()) {
             Node newNode = graph.findDuplicate(node);
@@ -162,11 +178,11 @@
         return false;
     }
 
-    public static void tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
+    public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
         if (node instanceof Canonicalizable) {
             METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
-            Debug.scope("CanonicalizeNode", node, new Runnable() {
-                public void run() {
+            return Debug.scope("CanonicalizeNode", node, new Callable<Boolean>(){
+                public Boolean call() {
                     ValueNode canonical = ((Canonicalizable) node).canonical(tool);
 //     cases:                                           original node:
 //                                         |Floating|Fixed-unconnected|Fixed-connected|
@@ -182,9 +198,9 @@
 //       X: must not happen (checked with assertions)
                     if (canonical == node) {
                         Debug.log("Canonicalizer: work on %s", node);
+                        return false;
                     } else {
                         Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
-
                         METRIC_CANONICALIZED_NODES.increment();
                         if (node instanceof FloatingNode) {
                             if (canonical == null) {
@@ -192,7 +208,7 @@
                                 graph.removeFloating((FloatingNode) node);
                             } else {
                                 // case 2
-                                assert !(canonical instanceof FixedNode) || canonical.predecessor() != null : node + " -> " + canonical +
+                                assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode) : node + " -> " + canonical +
                                                 " : replacement should be floating or fixed and connected";
                                 graph.replaceFloating((FloatingNode) node, canonical);
                             }
@@ -218,6 +234,7 @@
                                 }
                             }
                         }
+                        return true;
                     }
                 }
             });
@@ -226,6 +243,7 @@
             METRIC_SIMPLIFICATION_CONSIDERED_NODES.increment();
             ((Simplifiable) node).simplify(tool);
         }
+        return false;
     }
 
     /**
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/EscapeAnalysisPhase.java	Mon Jul 09 14:22:22 2012 +0200
@@ -169,7 +169,7 @@
 
             if (virtual.fieldsCount() > 0) {
                 final BlockExitState startState = new BlockExitState(escapeFields, virtual);
-                final PostOrderNodeIterator<?> iterator = new PostOrderNodeIterator<BlockExitState>(next, startState) {
+                new PostOrderNodeIterator<BlockExitState>(next, startState) {
                     @Override
                     protected void node(FixedNode curNode) {
                         op.updateState(virtual, curNode, fields, state.fieldState);
@@ -183,8 +183,7 @@
                             ((StateSplit) curNode).stateAfter().addVirtualObjectMapping(v);
                         }
                     }
-                };
-                iterator.apply();
+                }.apply();
             }
         }
     }
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Graph.java	Mon Jul 09 14:22:22 2012 +0200
@@ -47,7 +47,6 @@
     private int deletedNodeCount;
     private GraphEventLog eventLog;
 
-    ArrayList<Node> usagesDropped = new ArrayList<>();
     InputChangedListener inputChanged;
     private final HashMap<CacheEntry, Node> cachedNodes = new HashMap<>();
 
@@ -149,16 +148,6 @@
         return node;
     }
 
-    public int getUsagesDroppedNodesCount() {
-        return usagesDropped.size();
-    }
-
-    public List<Node> getAndCleanUsagesDroppedNodes() {
-        ArrayList<Node> result = usagesDropped;
-        usagesDropped = new ArrayList<>();
-        return result;
-    }
-
     public interface InputChangedListener {
         void inputChanged(Node node);
     }
@@ -322,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	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Mon Jul 09 14:22:22 2012 +0200
@@ -279,9 +279,6 @@
 
     private boolean removeThisFromUsages(Node n) {
         if (n.usages.remove(this)) {
-            if (n.usages.size() == 0) {
-                graph.usagesDropped.add(n);
-            }
             return true;
         } else {
             return false;
@@ -492,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	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeClass.java	Mon Jul 09 14:22:22 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.graph/src/com/oracle/graal/graph/NodeList.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/NodeList.java	Mon Jul 09 14:22:22 2012 +0200
@@ -55,7 +55,7 @@
             this.nodes = new Node[elements.length];
             for (int i = 0; i < elements.length; i++) {
                 this.nodes[i] = elements[i];
-                assert this.nodes[i] == null || !this.nodes[i].isDeleted();
+                assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i];
             }
         }
     }
@@ -254,6 +254,13 @@
         return (List<T>) Arrays.asList(Arrays.copyOf(this.nodes, this.size));
     }
 
+    @Override
+    public void snapshotTo(List<T> to) {
+        for (int i = 0; i < size; i++) {
+            to.add(get(i));
+        }
+    }
+
     @SuppressWarnings("unchecked")
     public void setAll(NodeList<T> values) {
         incModCount();
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/AbstractNodeIterable.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/AbstractNodeIterable.java	Mon Jul 09 14:22:22 2012 +0200
@@ -65,6 +65,12 @@
         return list;
     }
     @Override
+    public void snapshotTo(List<T> to) {
+        for (T n : this) {
+            to.add(n);
+        }
+    }
+    @Override
     public T first() {
         Iterator<T> iterator = iterator();
         if (iterator.hasNext()) {
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/iterators/NodeIterable.java	Mon Jul 09 14:22:22 2012 +0200
@@ -44,6 +44,8 @@
 
     List<T> snapshot();
 
+    void snapshotTo(List<T> to);
+
     T first();
 
     int count();
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotDebugConfig.java	Mon Jul 09 14:22:22 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	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/Block.java	Mon Jul 09 14:22:22 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	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.lir/src/com/oracle/graal/lir/cfg/CFGVerifier.java	Mon Jul 09 14:22:22 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()) {
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/NewArrayNode.java	Mon Jul 09 14:22:22 2012 +0200
@@ -130,12 +130,13 @@
                 AccessIndexedNode x = (AccessIndexedNode) current;
                 if (GraphUtil.unProxify(x.array()) == node) {
                     int index = ((AccessIndexedNode) current).index().asConstant().asInt();
+                    StructuredGraph graph = (StructuredGraph) x.graph();
                     if (current instanceof LoadIndexedNode) {
                         x.replaceAtUsages(fieldState[index]);
-                        ((StructuredGraph) x.graph()).removeFixed(x);
+                        graph.removeFixed(x);
                     } else if (current instanceof StoreIndexedNode) {
                         fieldState[index] = ((StoreIndexedNode) x).value();
-                        ((StructuredGraph) x.graph()).removeFixed(x);
+                        graph.removeFixed(x);
                         return index;
                     }
                 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Mon Jul 09 14:22:22 2012 +0200
@@ -22,21 +22,24 @@
  */
 package com.oracle.graal.nodes.util;
 
-import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
 import java.util.*;
 
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.iterators.*;
-import com.oracle.graal.graph.iterators.NodePredicates.PositiveTypePredicate;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.calc.*;
 import com.oracle.graal.nodes.java.*;
 
 public class GraphUtil {
 
-    private static final PositiveTypePredicate FLOATING = isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class);
+    private static final NodePredicate FLOATING = new NodePredicate() {
+        @Override
+        public final boolean  apply(Node n) {
+            //isA(FloatingNode.class).or(VirtualState.class).or(CallTargetNode.class)
+            return n instanceof FloatingNode || n instanceof VirtualState || n instanceof CallTargetNode;
+        }
+    };
 
     public static void killCFG(FixedNode node) {
         assert node.isAlive();
--- /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:22:22 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:22:22 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	Sat Jul 07 12:53:00 2012 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Mon Jul 09 14:22:22 2012 +0200
@@ -79,12 +79,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();
@@ -93,10 +93,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	Sat Jul 07 12:53:00 2012 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Coordinator/src/com/sun/hotspot/igv/coordinator/OutlineTopComponent.java	Mon Jul 09 14:22:22 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	Sat Jul 07 12:53:00 2012 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputGraph.java	Mon Jul 09 14:22:22 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:22:22 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:22:22 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:22:22 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	Sat Jul 07 12:53:00 2012 +0200
+++ b/src/share/tools/IdealGraphVisualizer/Settings/src/com/sun/hotspot/igv/settings/Settings.java	Mon Jul 09 14:22:22 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");