changeset 19986:3c78119de0cd

Layout and display improvements and bug fixes for IdealGraphVisualizer.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 21 Mar 2015 15:41:38 +0100
parents b5516d27d657
children 414c068bd862
files src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java
diffstat 23 files changed, 350 insertions(+), 333 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/InputEdge.java	Sat Mar 21 15:41:38 2015 +0100
@@ -86,7 +86,7 @@
         this.to = to;
         this.state = State.SAME;
         this.label = label;
-        this.type = type;
+        this.type = type.intern();
     }
 
     static WeakHashMap<InputEdge, WeakReference<InputEdge>> immutableCache = new WeakHashMap<>();
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/Properties.java	Sat Mar 21 15:41:38 2015 +0100
@@ -271,7 +271,7 @@
             } else {
                 sb.append(", ");
             }
-            sb.append(p[0] + "=" + p[1]);
+            sb.append(p[0]).append("=").append(p[1]);
         }
         return sb.append("]").toString();
     }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/BinaryParser.java	Sat Mar 21 15:41:38 2015 +0100
@@ -706,7 +706,8 @@
     private void parseNodes(InputGraph graph) throws IOException {
         int count = readInt();
         Map<String, Object> props = new HashMap<>();
-        List<Edge> edges = new LinkedList<>();
+        List<Edge> inputEdges = new ArrayList<>(count);
+        List<Edge> succEdges = new ArrayList<>(count);
         for (int i = 0; i < count; i++) {
             int id = readInt();
             InputNode node = new InputNode(id);
@@ -733,7 +734,7 @@
                     props.put(key, value);
                 }
             }
-            int edgesStart = edges.size();
+            ArrayList<Edge> currentEdges = new ArrayList<>();
             int portNum = 0;
             for (TypedPort p : nodeClass.inputs) {
                 if (p.isList) {
@@ -741,14 +742,18 @@
                     for (int j = 0; j < size; j++) {
                         int in = readInt();
                         if (in >= 0) {
-                            edges.add(new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true));
+                            Edge e = new Edge(in, id, (char) (preds + portNum), p.name + "[" + j + "]", p.type.toString(Length.S), true);
+                            currentEdges.add(e);
+                            inputEdges.add(e);
                             portNum++;
                         }
                     }
                 } else {
                     int in = readInt();
                     if (in >= 0) {
-                        edges.add(new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true));
+                        Edge e = new Edge(in, id, (char) (preds + portNum), p.name, p.type.toString(Length.S), true);
+                        currentEdges.add(e);
+                        inputEdges.add(e);
                         portNum++;
                     }
                 }
@@ -761,19 +766,23 @@
                     for (int j = 0; j < size; j++) {
                         int sux = readInt();
                         if (sux >= 0) {
-                            edges.add(new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false));
+                            Edge e = new Edge(id, sux, (char) portNum, p.name + "[" + j + "]", "Successor", false);
+                            currentEdges.add(e);
+                            succEdges.add(e);
                             portNum++;
                         }
                     }
                 } else {
                     int sux = readInt();
                     if (sux >= 0) {
-                        edges.add(new Edge(id, sux, (char) portNum, p.name, "Successor", false));
+                        Edge e = new Edge(id, sux, (char) portNum, p.name, "Successor", false);
+                        currentEdges.add(e);
+                        succEdges.add(e);
                         portNum++;
                     }
                 }
             }
-            properties.setProperty("name", createName(edges.subList(edgesStart, edges.size()), props, nodeClass.nameTemplate));
+            properties.setProperty("name", createName(currentEdges, props, nodeClass.nameTemplate));
             properties.setProperty("class", nodeClass.className);
             switch (nodeClass.className) {
                 case "BeginNode":
@@ -786,9 +795,20 @@
             graph.addNode(node);
             props.clear();
         }
-        for (Edge e : edges) {
-            char fromIndex = e.input ? 1 : e.num;
-            char toIndex = e.input ? e.num : 0;
+        
+        Set<InputNode> nodesWithSuccessor = new HashSet<>();
+        
+        for (Edge e : succEdges) {
+            assert !e.input;
+            char fromIndex = e.num;
+            nodesWithSuccessor.add(graph.getNode(e.from));
+            char toIndex = 0;
+            graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type));
+        }
+        for (Edge e : inputEdges) {
+            assert e.input;
+            char fromIndex = (char) (nodesWithSuccessor.contains(graph.getNode(e.from)) ? 1 : 0);
+            char toIndex = e.num;
             graph.addEdge(InputEdge.createImmutable(fromIndex, toIndex, e.from, e.to, e.label, e.type));
         }
     }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Parser.java	Sat Mar 21 15:41:38 2015 +0100
@@ -75,6 +75,7 @@
     public static final String NODE_ID_PROPERTY = "id";
     public static final String FROM_PROPERTY = "from";
     public static final String TO_PROPERTY = "to";
+    public static final String TYPE_PROPERTY = "type";
     public static final String PROPERTY_NAME_PROPERTY = "name";
     public static final String GRAPH_NAME_PROPERTY = "name";
     public static final String FROM_INDEX_PROPERTY = "fromIndex";
@@ -387,6 +388,7 @@
             int from = -1;
             int to = -1;
             String label = null;
+            String type = null;
 
             try {
                 String fromIndexString = readAttribute(FROM_INDEX_PROPERTY);
@@ -403,6 +405,7 @@
                 }
 
                 label = readAttribute(LABEL_PROPERTY);
+                type = readAttribute(TYPE_PROPERTY);
 
                 from = lookupID(readRequiredAttribute(FROM_PROPERTY));
                 to = lookupID(readRequiredAttribute(TO_PROPERTY));
@@ -410,7 +413,7 @@
                 throw new SAXException(e);
             }
 
-            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, "");
+            InputEdge conn = new InputEdge((char) fromIndex, (char) toIndex, from, to, label, type == null ? "" : type);
             return start(conn);
         }
 
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/Printer.java	Sat Mar 21 15:41:38 2015 +0100
@@ -240,6 +240,7 @@
         }
         p.setProperty(Parser.TO_PROPERTY, Integer.toString(edge.getTo()));
         p.setProperty(Parser.FROM_PROPERTY, Integer.toString(edge.getFrom()));
+        p.setProperty(Parser.TYPE_PROPERTY, edge.getType());
         return p;
     }
 }
--- a/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Data/src/com/sun/hotspot/igv/data/serialization/graphdocument.xsd	Sat Mar 21 15:41:38 2015 +0100
@@ -109,6 +109,7 @@
         <xsd:attribute name="from" type="xsd:int" use="required" />
         <xsd:attribute name="to" type="xsd:int" use="required" />
         <xsd:attribute name="label" type="xsd:string" use="optional" />
+        <xsd:attribute name="type" type="xsd:string" use="optional" />
         <xsd:attribute name="fromIndex" type="xsd:int" use="optional" />
         
         <!-- These are aliases and should be mutually exclusive -->
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/GraalEdgeColorFilter.java	Sat Mar 21 15:41:38 2015 +0100
@@ -33,7 +33,6 @@
 import java.awt.Color;
 import java.util.HashMap;
 import java.util.List;
-import java.util.regex.Pattern;
 
 /**
  * Filter that colors usage and successor edges differently.
@@ -42,7 +41,7 @@
  */
 public class GraalEdgeColorFilter extends AbstractFilter {
 
-    private HashMap<String,Color> usageColor = new HashMap<>();
+    private final HashMap<String,Color> usageColor = new HashMap<>();
     private Color otherUsageColor = Color.BLACK;
 
     public GraalEdgeColorFilter() {
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/beginend.filter	Fri Mar 20 18:33:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-var f = new CombineFilter("Combine Filter");
-f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", ".*"), new Properties.RegexpPropertyMatcher("class", "BeginNode"), false, "shortName"));
-f.addRule(new CombineFilter.CombineRule(new Properties.RegexpPropertyMatcher("class", "EndNode"), new Properties.RegexpPropertyMatcher("class", ".*"), true, "shortName"));
-f.apply(graph);
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/framestatelocks.filter	Fri Mar 20 18:33:31 2015 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-colorize("class", "FrameState", red);
-colorize("locks", "", gray);
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/filters/reduceEdges.filter	Sat Mar 21 15:41:38 2015 +0100
@@ -0,0 +1,3 @@
+split("class", "ConstantLocationNode");
+split("class", "ParameterNode");
+split("class", "ConstantNode");
--- a/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graal/src/com/sun/hotspot/igv/graal/layer.xml	Sat Mar 21 15:41:38 2015 +0100
@@ -18,7 +18,7 @@
             <attr name="enabled" boolvalue="false"/>
         </file>
         
-        <file name="Graal Reduce Begin-End" url="filters/beginend.filter">
+        <file name="Graal Reduce Edges" url="filters/reduceEdges.filter">
             <attr name="enabled" boolvalue="false"/>
         </file>
         
@@ -26,10 +26,6 @@
             <attr name="enabled" boolvalue="false"/>
         </file>
         
-        <file name="Graal Mark FrameState With Lock" url="filters/framestatelocks.filter">
-            <attr name="enabled" boolvalue="false"/>
-        </file>
-        
         <file name="Graal Call Analysis" url="filters/callgraph.filter">
             <attr name="enabled" boolvalue="false"/>
         </file>
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Diagram.java	Sat Mar 21 15:41:38 2015 +0100
@@ -41,8 +41,9 @@
     private InputGraph graph;
     private int curId;
     private String nodeText;
-    private Font font;
-    private Font slotFont;
+    private final Font font;
+    private final Font slotFont;
+    private final Font boldFont;
 
     public Font getFont() {
         return font;
@@ -51,12 +52,17 @@
     public Font getSlotFont() {
         return slotFont;
     }
+
+    public Font getBoldFont() {
+        return boldFont;
+    }
     
     private Diagram() {
         figures = new ArrayList<>();
         this.nodeText = "";
-        this.font = new Font("Arial", Font.PLAIN, 13);
+        this.font = new Font("Arial", Font.PLAIN, 12);
         this.slotFont = new Font("Arial", Font.PLAIN, 10);
+        this.boldFont = this.font.deriveFont(Font.BOLD);
     }
 
     public String getNodeText() {
--- a/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Graph/src/com/sun/hotspot/igv/graph/Figure.java	Sat Mar 21 15:41:38 2015 +0100
@@ -33,14 +33,10 @@
 import java.util.List;
 import java.util.*;
 
-/**
- *
- * @author Thomas Wuerthinger
- */
 public class Figure extends Properties.Entity implements Source.Provider, Vertex {
 
-    public static final int INSET = 12;
-    public static int SLOT_WIDTH = 12;
+    public static final int INSET = 8;
+    public static int SLOT_WIDTH = 10;
     public static final int OVERLAPPING = 6;
     public static final int SLOT_START = 4;
     public static final int SLOT_OFFSET = 8;
--- a/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/HierarchicalLayout/src/com/sun/hotspot/igv/hierarchicallayout/HierarchicalLayoutManager.java	Sat Mar 21 15:41:38 2015 +0100
@@ -43,8 +43,8 @@
     public static final int CROSSING_ITERATIONS = 2;
     public static final int DUMMY_HEIGHT = 1;
     public static final int DUMMY_WIDTH = 1;
-    public static final int X_OFFSET = 9;
-    public static final int LAYER_OFFSET = 30;
+    public static final int X_OFFSET = 8;
+    public static final int LAYER_OFFSET = 8;
     public static final int MAX_LAYER_LENGTH = -1;
     public static final int MIN_LAYER_DIFFERENCE = 1;
     public static final int VIP_BONUS = 10;
@@ -75,8 +75,6 @@
     private LayoutGraph graph;
     private List<LayoutNode>[] layers;
     private int layerCount;
-    private Set<? extends Vertex> firstLayerHint;
-    private Set<? extends Vertex> lastLayerHint;
     private Set<? extends Link> importantLinks;
     private Set<Link> linksToFollow;
 
@@ -181,17 +179,15 @@
 
     @Override
     public void doLayout(LayoutGraph graph) {
-        doLayout(graph, new HashSet<Vertex>(), new HashSet<Vertex>(), new HashSet<Link>());
+        doLayout(graph, new HashSet<Link>());
 
     }
 
     @Override
-    public void doLayout(LayoutGraph graph, Set<? extends Vertex> firstLayerHint, Set<? extends Vertex> lastLayerHint, Set<? extends Link> importantLinks) {
+    public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks) {
 
         this.importantLinks = importantLinks;
         this.graph = graph;
-        this.firstLayerHint = firstLayerHint;
-        this.lastLayerHint = lastLayerHint;
 
         vertexToLayoutNode = new HashMap<>();
         reversedLinks = new HashSet<>();
@@ -219,7 +215,6 @@
             }
 
             for (LayoutEdge e : tmpArr) {
-                //System.out.println("Removed " + e);
                 e.from.succs.remove(e);
                 e.to.preds.remove(e);
             }
@@ -302,8 +297,6 @@
 
                         Collections.reverse(points);
 
-
-
                         if (cur.vertex == null && cur.preds.size() == 0) {
 
                             if (reversedLinkEndPoints.containsKey(e.link)) {
@@ -364,7 +357,7 @@
                         LayoutNode cur = e.to;
                         LayoutNode other = e.from;
                         LayoutEdge curEdge = e;
-                        while (cur.vertex == null && cur.succs.size() != 0) {
+                        while (cur.vertex == null && !cur.succs.isEmpty()) {
                             if (points.size() > 1 && points.get(points.size() - 1).x == cur.x + cur.width / 2 && points.get(points.size() - 2).x == cur.x + cur.width / 2) {
                                 points.remove(points.size() - 1);
                             }
@@ -373,7 +366,7 @@
                                 points.remove(points.size() - 1);
                             }
                             points.add(new Point(cur.x + cur.width / 2, cur.y + cur.height));
-                            if (cur.succs.size() == 0) {
+                            if (cur.succs.isEmpty()) {
                                 break;
                             }
                             assert cur.succs.size() == 1;
@@ -381,15 +374,13 @@
                             cur = curEdge.to;
                         }
 
-
                         p = new Point(cur.x + curEdge.relativeTo, cur.y + cur.yOffset + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y));
                         points.add(p);
                         if (curEdge.to.inOffsets.containsKey(curEdge.relativeTo)) {
                             points.add(new Point(p.x, p.y + curEdge.to.inOffsets.get(curEdge.relativeTo) + ((curEdge.link == null) ? 0 : curEdge.link.getTo().getRelativePosition().y)));
                         }
 
-
-                        if (cur.succs.size() == 0 && cur.vertex == null) {
+                        if (cur.succs.isEmpty() && cur.vertex == null) {
                             if (reversedLinkStartPoints.containsKey(e.link)) {
                                 for (Point p1 : reversedLinkStartPoints.get(e.link)) {
                                     points.add(0, new Point(p1.x + other.x, p1.y + other.y));
@@ -528,13 +519,34 @@
     private static final Comparator<LayoutNode> nodeProcessingDownComparator = new Comparator<LayoutNode>() {
         @Override
         public int compare(LayoutNode n1, LayoutNode n2) {
+            int n1VIP = 0;
+            for (LayoutEdge e : n1.preds) {
+                if (e.vip) {
+                    n1VIP++;
+                }
+            }
+            int n2VIP = 0;
+            for (LayoutEdge e : n1.preds) {
+                if (e.vip) {
+                    n2VIP++;
+                }
+            }
+            if (n1VIP != n2VIP) {
+                return n2VIP - n1VIP;
+            }
             if (n1.vertex == null) {
                 if (n2.vertex == null) {
                     return 0;
                 }
+                if (n1.preds.size() == 1 && n1.preds.get(0).from.vertex != null) {
+                    return 1;
+                }
                 return -1;
             }
             if (n2.vertex == null) {
+                if (n2.preds.size() == 1 && n2.preds.get(0).from.vertex != null) {
+                    return -1;
+                }
                 return 1;
             }
             return n1.preds.size() - n2.preds.size();
@@ -544,15 +556,36 @@
 
         @Override
         public int compare(LayoutNode n1, LayoutNode n2) {
+            int n1VIP = 0;
+            for (LayoutEdge e : n1.succs) {
+                if (e.vip) {
+                    n1VIP++;
+                }
+            }
+            int n2VIP = 0;
+            for (LayoutEdge e : n1.succs) {
+                if (e.vip) {
+                    n2VIP++;
+                }
+            }
             if (n1.vertex == null) {
                 if (n2.vertex == null) {
                     return 0;
                 }
+                if (n1.succs.size() == 1 && n1.succs.get(0).to.vertex != null) {
+                    return 1;
+                }
                 return -1;
             }
             if (n2.vertex == null) {
+                if (n2.succs.size() == 1 && n2.succs.get(0).to.vertex != null) {
+                    return -1;
+                }
                 return 1;
             }
+            if (n1VIP != n2VIP) {
+                return n2VIP - n1VIP;
+            }
             return n1.succs.size() - n2.succs.size();
         }
     };
@@ -568,7 +601,7 @@
                 n.x = space[n.layer].get(n.pos);
             }
         }
-        
+
         @SuppressWarnings("unchecked")
         private void createArrays() {
             space = new ArrayList[layers.length];
@@ -600,13 +633,23 @@
             initialPositions();
             for (int i = 0; i < SWEEP_ITERATIONS; i++) {
                 sweepDown();
+                adjustSpace();
                 sweepUp();
+                adjustSpace();
             }
- 
+
             sweepDown();
-            //for (int i = 0; i < SWEEP_ITERATIONS; i++) {
-            //    doubleSweep();
-            //}            
+        }
+
+        private void adjustSpace() {
+            for (int i = 0; i < layers.length; i++) {
+                //               space[i] = new ArrayList<>();
+                int curX = 0;
+                for (LayoutNode n : layers[i]) {
+                    space[i].add(n.x);
+//                    curX += n.width + xOffset;
+                }
+            }
         }
 
         private int calculateOptimalDown(LayoutNode n) {
@@ -629,7 +672,7 @@
             if (n.preds.size() == n.succs.size()) {
                 return n.x;
             }
-            
+
             int[] values = new int[n.preds.size() + n.succs.size()];
             int i = 0;
 
@@ -747,7 +790,7 @@
                     n.x = pos;
                 }
 
-                assert minX <= maxX;
+                assert minX <= maxX : minX + " vs " + maxX;
             }
 
             treeSet.add(n);
@@ -769,7 +812,7 @@
                 assert n.layer < layerCount;
             }
         }
-        
+
         @SuppressWarnings("unchecked")
         private void createLayers() {
             layers = new List[layerCount];
@@ -789,7 +832,7 @@
                 if (n.layer == 0) {
                     layers[0].add(n);
                     visited.add(n);
-                } else if (n.preds.size() == 0) {
+                } else if (n.preds.isEmpty()) {
                     layers[n.layer].add(n);
                     visited.add(n);
                 }
@@ -806,7 +849,6 @@
                 }
             }
 
-
             updatePositions();
 
             initX();
@@ -816,11 +858,7 @@
                 downSweep();
                 upSweep();
             }
-            if (reversedLinks.isEmpty()) {
-                // This graph seems to be a tree or forest.
-                // A final down-sweep will usually give us a better layout.
-                downSweep();
-            }
+            downSweep();
         }
 
         private void initX() {
@@ -869,8 +907,8 @@
                         if (e.vip) {
                             factor = VIP_BONUS;
                         }
-                        sum += cur*factor;
-                        count+=factor;
+                        sum += cur * factor;
+                        count += factor;
                     }
 
                     if (count > 0) {
@@ -879,7 +917,6 @@
                     }
                 }
 
-
                 updateCrossingNumbers(i, true);
                 Collections.sort(layers[i], crossingNodeComparator);
                 updateXOfLayer(i);
@@ -940,8 +977,8 @@
                         if (e.vip) {
                             factor = VIP_BONUS;
                         }
-                        sum += cur*factor;
-                        count+=factor;
+                        sum += cur * factor;
+                        count += factor;
                     }
 
                     if (count > 0) {
@@ -1012,7 +1049,7 @@
                 }
 
                 curY += maxHeight + baseLine + bottomBaseLine;
-                curY += layerOffset + (int) Math.sqrt(maxXOffset);
+                curY += layerOffset + ((int) (Math.sqrt(maxXOffset) * 1.5));
             }
         }
     }
@@ -1041,7 +1078,6 @@
         protected void run() {
             oldNodeCount = nodes.size();
 
-
             if (combine == Combine.SAME_OUTPUTS) {
 
                 Comparator<LayoutEdge> comparator = new Comparator<LayoutEdge>() {
@@ -1154,7 +1190,6 @@
                                     maxLayer = Math.max(maxLayer, curEdge.to.layer);
                                 }
 
-
                                 int cnt = maxLayer - n.layer - 1;
                                 LayoutEdge[] edges = new LayoutEdge[cnt];
                                 LayoutNode[] nodes = new LayoutNode[cnt];
@@ -1279,91 +1314,109 @@
 
         @Override
         protected void run() {
-
-            List<LayoutNode> insertOrder = new ArrayList<>();
+            assignLayerDownwards();
+            assignLayerUpwards();
+        }
 
-            HashSet<LayoutNode> set = new HashSet<>();
+        private void assignLayerDownwards() {
+            ArrayList<LayoutNode> hull = new ArrayList<>();
             for (LayoutNode n : nodes) {
-                if (n.preds.size() == 0) {
-                    set.add(n);
-                    insertOrder.add(n);
+                if (n.preds.isEmpty()) {
+                    hull.add(n);
                     n.layer = 0;
                 }
             }
 
             int z = minLayerDifference;
-            HashSet<LayoutNode> newSet = new HashSet<>();
-            HashSet<LayoutNode> failed = new HashSet<>();
-            while (!set.isEmpty()) {
-
-                newSet.clear();
-                failed.clear();
-
-                for (LayoutNode n : set) {
-
+            while (!hull.isEmpty()) {
+                ArrayList<LayoutNode> newSet = new ArrayList<>();
+                for (LayoutNode n : hull) {
                     for (LayoutEdge se : n.succs) {
                         LayoutNode s = se.to;
-                        if (!newSet.contains(s) && !failed.contains(s)) {
-                            boolean ok = true;
+                        if (s.layer != -1) {
+                            // This node was assigned before.
+                        } else {
+                            boolean unassignedPred = false;
                             for (LayoutEdge pe : s.preds) {
                                 LayoutNode p = pe.from;
-                                if (p.layer == -1) {
-                                    ok = false;
+                                if (p.layer == -1 || p.layer >= z) {
+                                    // This now has an unscheduled successor or a successor that was scheduled only in this round.
+                                    unassignedPred = true;
                                     break;
                                 }
                             }
 
-                            if (ok) {
+                            if (unassignedPred) {
+                                // This successor node can not yet be assigned.
+                            } else {
+                                s.layer = z;
                                 newSet.add(s);
-                            } else {
-                                failed.add(s);
                             }
                         }
                     }
-
                 }
 
-                for (LayoutNode n : newSet) {
-                    n.layer = z;
-                    insertOrder.add(n);
-                }
-
-                // Swap sets
-                HashSet<LayoutNode> tmp = set;
-                set = newSet;
-                newSet = tmp;
+                hull = newSet;
                 z += minLayerDifference;
             }
 
-            optimize(insertOrder);
+            layerCount = z - minLayerDifference;
+            for (LayoutNode n : nodes) {
+                n.layer = (layerCount - 1 - n.layer);
+            }
+        }
+
+        private void assignLayerUpwards() {
+            ArrayList<LayoutNode> hull = new ArrayList<>();
+            for (LayoutNode n : nodes) {
+                if (n.succs.isEmpty()) {
+                    hull.add(n);
+                } else {
+                    n.layer = -1;
+                }
+            }
+
+            int z = minLayerDifference;
+            while (!hull.isEmpty()) {
+                ArrayList<LayoutNode> newSet = new ArrayList<>();
+                for (LayoutNode n : hull) {
+                    if (n.layer < z) {
+                        for (LayoutEdge se : n.preds) {
+                            LayoutNode s = se.from;
+                            if (s.layer != -1) {
+                                // This node was assigned before.
+                            } else {
+                                boolean unassignedSucc = false;
+                                for (LayoutEdge pe : s.succs) {
+                                    LayoutNode p = pe.to;
+                                    if (p.layer == -1 || p.layer >= z) {
+                                        // This now has an unscheduled successor or a successor that was scheduled only in this round.
+                                        unassignedSucc = true;
+                                        break;
+                                    }
+                                }
+
+                                if (unassignedSucc) {
+                                    // This predecessor node can not yet be assigned.
+                                } else {
+                                    s.layer = z;
+                                    newSet.add(s);
+                                }
+                            }
+                        }
+                    } else {
+                        newSet.add(n);
+                    }
+                }
+
+                hull = newSet;
+                z += minLayerDifference;
+            }
 
             layerCount = z - minLayerDifference;
 
-            for (Vertex v : lastLayerHint) {
-
-                LayoutNode n = vertexToLayoutNode.get(v);
-                assert n.succs.size() == 0;
-                n.layer = layerCount - 1;
-            }
-
-            for (Vertex v : firstLayerHint) {
-                LayoutNode n = vertexToLayoutNode.get(v);
-                assert n.preds.size() == 0;
-                n.layer = 0;
-                assert n.layer == 0;
-            }
-        }
-
-        public void optimize(List<LayoutNode> insertOrder) {
-            for (int i = insertOrder.size() - 1; i >= 0; i--) {
-                LayoutNode cur = insertOrder.get(i);
-                if (cur.succs.size() > cur.preds.size()) {
-                    int minLayer = cur.succs.get(0).to.layer;
-                    for (LayoutEdge e : cur.succs) {
-                        minLayer = Math.min(minLayer, e.to.layer);
-                    }
-                    cur.layer = minLayer - 1;
-                }
+            for (LayoutNode n : nodes) {
+                n.layer = (layerCount - 1 - n.layer);
             }
         }
 
@@ -1415,7 +1468,6 @@
                 }
             }
 
-
             // Start DFS and reverse back edges
             visited = new HashSet<>();
             active = new HashSet<>();
@@ -1423,7 +1475,6 @@
                 DFS(node);
             }
 
-
             for (LayoutNode node : nodes) {
 
                 SortedSet<Integer> reversedDown = new TreeSet<>();
@@ -1434,7 +1485,6 @@
                     }
                 }
 
-
                 SortedSet<Integer> reversedUp = null;
                 if (reversedDown.size() == 0) {
                     reversedUp = new TreeSet<>(Collections.reverseOrder());
@@ -1522,7 +1572,6 @@
                     curX += offset;
                     node.bottomYOffset += offset;
 
-
                     endPoints.add(new Point(pos, node.height));
                     endPoints.add(new Point(pos, oldNodeHeight));
                     for (LayoutEdge e : reversedPreds) {
@@ -1530,7 +1579,6 @@
                     }
                 }
 
-
                 if (minX < 0) {
                     for (LayoutEdge e : node.preds) {
                         e.relativeTo -= minX;
@@ -1701,12 +1749,12 @@
                 edge.from.succs.add(edge);
                 edge.to.preds.add(edge);
                 edge.vip = l.isVIP();
-            //assert edge.from != edge.to; // No self-loops allowed
+                //assert edge.from != edge.to; // No self-loops allowed
             }
 
             for (Link l : importantLinks) {
-                if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex()) ||
-                        vertexToLayoutNode.containsKey(l.getTo().getVertex())) {
+                if (!vertexToLayoutNode.containsKey(l.getFrom().getVertex())
+                        || vertexToLayoutNode.containsKey(l.getTo().getVertex())) {
                     continue;
                 }
                 LayoutNode from = vertexToLayoutNode.get(l.getFrom().getVertex());
--- a/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Layout/src/com/sun/hotspot/igv/layout/LayoutManager.java	Sat Mar 21 15:41:38 2015 +0100
@@ -33,7 +33,7 @@
 
     public void doLayout(LayoutGraph graph);
 
-    public void doLayout(LayoutGraph graph, Set<? extends Vertex> firstLayerHint, Set<? extends Vertex> lastLayerHint, Set<? extends Link> importantLinks);
+    public void doLayout(LayoutGraph graph, Set<? extends Link> importantLinks);
 
     public void doRouting(LayoutGraph graph);
 }
--- a/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/Util/src/com/sun/hotspot/igv/util/ColorIcon.java	Sat Mar 21 15:41:38 2015 +0100
@@ -34,7 +34,7 @@
  */
 public class ColorIcon implements Icon {
 
-    private Color color;
+    private final Color color;
 
     public ColorIcon(Color c) {
         color = c;
@@ -42,8 +42,10 @@
 
     @Override
     public void paintIcon(Component c, Graphics g, int x, int y) {
+        Color oldColor = g.getColor();
         g.setColor(color);
         g.fillRect(x, y, 16, 16);
+        g.setColor(oldColor);
     }
 
     @Override
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramScene.java	Sat Mar 21 15:41:38 2015 +0100
@@ -71,6 +71,7 @@
     private Lookup lookup;
     private InstanceContent content;
     private Action[] actions;
+    private Action[] actionsWithSelection;
     private LayerWidget connectionLayer;
     private JScrollPane scrollPane;
     private UndoRedo.Manager undoRedoManager;
@@ -100,7 +101,7 @@
     public static final float ZOOM_MAX_FACTOR = 3.0f;
     public static final float ZOOM_MIN_FACTOR = 0.0f;//0.15f;
     public static final float ZOOM_INCREMENT = 1.5f;
-    public static final int SLOT_OFFSET = 6;
+    public static final int SLOT_OFFSET = 8;
     public static final int ANIMATION_LIMIT = 40;
     
     private PopupMenuProvider popupMenuProvider = new PopupMenuProvider() {
@@ -374,9 +375,10 @@
         }
     };
 
-    public DiagramScene(Action[] actions, DiagramViewModel model) {
+    public DiagramScene(Action[] actions, Action[] actionsWithSelection, DiagramViewModel model) {
 
         this.actions = actions;
+        this.actionsWithSelection = actionsWithSelection;
 
         content = new InstanceContent();
         lookup = new AbstractLookup(content);
@@ -399,6 +401,9 @@
         blockLayer = new LayerWidget(this);
         this.addChild(blockLayer);
 
+        connectionLayer = new LayerWidget(this);
+        this.addChild(connectionLayer);
+
         mainLayer = new LayerWidget(this);
         this.addChild(mainLayer);
 
@@ -410,9 +415,6 @@
         bottomRight.setPreferredLocation(new Point(-BORDER_SIZE, -BORDER_SIZE));
         this.addChild(bottomRight);
 
-        connectionLayer = new LayerWidget(this);
-        this.addChild(connectionLayer);
-
         LayerWidget selectionLayer = new LayerWidget(this);
         this.addChild(selectionLayer);
 
@@ -451,12 +453,21 @@
     }
     
     public boolean isAllVisible() {
-        return getModel().getHiddenNodes().size() == 0;
+        return getModel().getHiddenNodes().isEmpty();
     }
 
     public Action createGotoAction(final Figure f) {
         final DiagramScene diagramScene = this;
-        Action a = new AbstractAction() {
+        String name = f.getLines()[0];
+
+        name += " (";
+
+        final boolean hidden = !this.getWidget(f, FigureWidget.class).isVisible();
+        if (hidden) {
+            name += "hidden";
+        }
+        name += ")";
+        Action a = new AbstractAction(name, new ColorIcon(f.getColor())) {
 
             @Override
             public void actionPerformed(ActionEvent e) {
@@ -465,16 +476,6 @@
         };
 
         a.setEnabled(true);
-        a.putValue(Action.SMALL_ICON, new ColorIcon(f.getColor()));
-        String name = f.getLines()[0];
-
-        name += " (";
-
-        if (!this.getWidget(f, FigureWidget.class).isVisible()) {
-            name += "hidden";
-        }
-        name += ")";
-        a.putValue(Action.NAME, name);
         return a;
     }
 
@@ -538,8 +539,6 @@
     }
 
     private void smallUpdate(boolean relayout) {
-
-        System.out.println("smallUpdate " + relayout);
         this.updateHiddenNodes(model.getHiddenNodes(), relayout);
         boolean b = this.getUndoRedoEnabled();
         this.setUndoRedoEnabled(false);
@@ -559,8 +558,6 @@
     }
 
     private void relayout(Set<Widget> oldVisibleWidgets) {
-        System.out.println("relayout called with old visible widgets: " + oldVisibleWidgets);
-
         Diagram diagram = getModel().getDiagramToView();
 
         HashSet<Figure> figures = new HashSet<>();
@@ -589,8 +586,6 @@
 
     private void relayoutWithoutLayout(Set<Widget> oldVisibleWidgets) {
 
-        System.out.println("relayout without layout with visible widgets: " + oldVisibleWidgets);
-
         Diagram diagram = getModel().getDiagramToView();
 
         int maxX = -BORDER_SIZE;
@@ -958,8 +953,6 @@
 
     private void updateHiddenNodes(Set<Integer> newHiddenNodes, boolean doRelayout) {
 
-        System.out.println("newHiddenNodes: " + newHiddenNodes);
-
         Diagram diagram = getModel().getDiagramToView();
         assert diagram != null;
 
@@ -1027,7 +1020,7 @@
     private void showFigure(Figure f) {
         HashSet<Integer> newHiddenNodes = new HashSet<>(getModel().getHiddenNodes());
         newHiddenNodes.removeAll(f.getSource().getSourceNodesAsSet());
-        updateHiddenNodes(newHiddenNodes, true);
+        this.model.setHiddenNodes(newHiddenNodes);
     }
 
     public void show(final Figure f) {
@@ -1062,7 +1055,12 @@
 
     public JPopupMenu createPopupMenu() {
         JPopupMenu menu = new JPopupMenu();
-        for (Action a : actions) {
+        
+        Action[] currentActions = actionsWithSelection;
+        if (this.getSelectedObjects().isEmpty()) {
+            currentActions = actions;
+        }
+        for (Action a : currentActions) {
             if (a == null) {
                 menu.addSeparator();
             } else {
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/DiagramViewModel.java	Sat Mar 21 15:41:38 2015 +0100
@@ -246,7 +246,7 @@
                         if (last == null) {
                             curColor = Color.green;
                         } else {
-                            if (last.equals(cur)) {
+                            if (last.equals(cur) && last.getProperties().equals(cur.getProperties())) {
                                 if (curColor == Color.black) {
                                     curColor = Color.white;
                                 }
@@ -268,7 +268,6 @@
     }
 
     public void showNot(final Set<Integer> nodes) {
-        System.out.println("Shownot called with " + nodes);
         setHiddenNodes(nodes);
     }
 
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/EditorTopComponent.java	Sat Mar 21 15:41:38 2015 +0100
@@ -178,12 +178,17 @@
             null,
             ZoomInAction.get(ZoomInAction.class),
             ZoomOutAction.get(ZoomOutAction.class),
+        };
+
+        
+        Action[] actionsWithSelection = new Action[]{
+            ExtractAction.get(ExtractAction.class),
+            ShowAllAction.get(HideAction.class),
             null,
             ExpandPredecessorsAction.get(ExpandPredecessorsAction.class),
             ExpandSuccessorsAction.get(ExpandSuccessorsAction.class)
         };
 
-
         initComponents();
 
         ToolbarPool.getDefault().setPreferredIconSize(16);
@@ -201,7 +206,7 @@
         JScrollPane pane = new JScrollPane(rangeSlider, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
         container.add(BorderLayout.CENTER, pane);
 
-        scene = new DiagramScene(actions, rangeSliderModel);
+        scene = new DiagramScene(actions, actionsWithSelection, rangeSliderModel);
         content = new InstanceContent();
         graphContent = new InstanceContent();
         this.associateLookup(new ProxyLookup(new Lookup[]{scene.getLookup(), new AbstractLookup(graphContent), new AbstractLookup(content)}));
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/FigureWidget.java	Sat Mar 21 15:41:38 2015 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2015, 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
@@ -62,11 +62,7 @@
 public class FigureWidget extends Widget implements Properties.Provider, PopupMenuProvider, DoubleClickHandler {
 
     public static final boolean VERTICAL_LAYOUT = true;
-    //public static final int MAX_STRING_LENGTH = 20;
     private static final double LABEL_ZOOM_FACTOR = 0.3;
-    private static final double ZOOM_FACTOR = 0.1;
-    private Font font;
-    private Font boldFont;
     private Figure figure;
     private Widget leftWidget;
     private Widget rightWidget;
@@ -74,7 +70,7 @@
     private ArrayList<LabelWidget> labelWidgets;
     private DiagramScene diagramScene;
     private boolean boundary;
-    private Node node;
+    private final Node node;
     private Widget dummyTop;
 
     public void setBoundary(boolean b) {
@@ -89,11 +85,10 @@
         return node;
     }
 
-	@Override
-	public boolean isHitAt(Point localLocation) {
-		return middleWidget.isHitAt(localLocation);
-	}
-    
+    @Override
+    public boolean isHitAt(Point localLocation) {
+        return middleWidget.isHitAt(localLocation);
+    }
 
     public FigureWidget(final Figure f, WidgetAction hoverAction, WidgetAction selectAction, DiagramScene scene, Widget parent) {
 
@@ -103,23 +98,20 @@
         assert this.getScene().getView() != null;
 
         this.figure = f;
-        font = f.getDiagram().getFont();
-        boldFont = f.getDiagram().getFont().deriveFont(Font.BOLD);
         this.setCheckClipping(true);
         this.diagramScene = scene;
         parent.addChild(this);
 
-	Widget outer = new Widget(scene);
-	outer.setBackground(f.getColor());
-	outer.setLayout(LayoutFactory.createOverlayLayout());
-	
+        Widget outer = new Widget(scene);
+        outer.setBackground(f.getColor());
+        outer.setLayout(LayoutFactory.createOverlayLayout());
+
         middleWidget = new Widget(scene);
         middleWidget.setLayout(LayoutFactory.createVerticalFlowLayout(LayoutFactory.SerialAlignment.CENTER, 0));
         middleWidget.setBackground(f.getColor());
         middleWidget.setOpaque(true);
-        //middleWidget.setBorder(BorderFactory.createLineBorder(Color.BLACK));
         middleWidget.getActions().addAction(new DoubleClickAction(this));
-	middleWidget.setCheckClipping(true);
+        middleWidget.setCheckClipping(true);
 
         labelWidgets = new ArrayList<>();
 
@@ -129,7 +121,6 @@
         dummyTop.setMinimumSize(new Dimension(Figure.INSET / 2, 1));
         middleWidget.addChild(dummyTop);
 
-
         for (String cur : strings) {
 
             String displayString = cur;
@@ -138,11 +129,11 @@
             labelWidgets.add(lw);
             middleWidget.addChild(lw);
             lw.setLabel(displayString);
-            lw.setFont(font);
+            lw.setFont(figure.getDiagram().getFont());
             lw.setForeground(Color.BLACK);
             lw.setAlignment(LabelWidget.Alignment.CENTER);
             lw.setVerticalAlignment(LabelWidget.VerticalAlignment.CENTER);
-	    lw.setBorder(BorderFactory.createEmptyBorder());
+            lw.setBorder(BorderFactory.createEmptyBorder());
         }
 
         Widget dummyBottom = new Widget(scene);
@@ -150,7 +141,6 @@
         middleWidget.addChild(dummyBottom);
 
         middleWidget.setPreferredBounds(new Rectangle(0, Figure.SLOT_WIDTH - Figure.OVERLAPPING, f.getWidth(), f.getHeight()));
-	//outer.addChild(middleWidget);
         this.addChild(middleWidget);
 
         // Initialize node for property sheet
@@ -178,49 +168,22 @@
     protected void notifyStateChanged(ObjectState previousState, ObjectState state) {
         super.notifyStateChanged(previousState, state);
 
-        Color borderColor = Color.BLACK;
-	Color innerBorderColor = getFigure().getColor();
-        int thickness = 1;
-        boolean repaint = false;
-        Font f = font;
-        if (state.isSelected() || state.isHighlighted()) {
-            thickness = 2;
-	}
-	if(state.isSelected()) {
-            f = boldFont;
-		innerBorderColor = borderColor;
-        } else {
-	}
-
-        if (state.isHighlighted()) {
-		innerBorderColor = borderColor = Color.BLUE;
-		repaint = true;
-        } else {
-		repaint = true;
-	}
-
-        if (state.isHovered() != previousState.isHovered()) {
-
-		/*
-            if (state.isHovered()) {
-                diagramScene.addAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet());
-            } else {
-                diagramScene.removeAllHighlighted(this.getFigure().getSource().getSourceNodesAsSet());
-            }*/
-            repaint = true;
+        Font font = this.figure.getDiagram().getFont();
+        if (state.isSelected()) {
+            font = this.figure.getDiagram().getBoldFont();
         }
 
-        if (state.isSelected() != previousState.isSelected()) {
-            repaint = true;
+        Color borderColor = Color.BLACK;
+        Color innerBorderColor = getFigure().getColor();
+        if (state.isHighlighted()) {
+            innerBorderColor = borderColor = Color.BLUE;
         }
 
-        if (repaint) {
-            middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1)));
-            for (LabelWidget labelWidget : labelWidgets) {
-                labelWidget.setFont(f);
-            }
-            repaint();
+        middleWidget.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(borderColor, 1), BorderFactory.createLineBorder(innerBorderColor, 1)));
+        for (LabelWidget labelWidget : labelWidgets) {
+            labelWidget.setFont(font);
         }
+        repaint();
     }
 
     public String getName() {
@@ -246,7 +209,6 @@
         }
 
         if (diagramScene.getZoomFactor() < LABEL_ZOOM_FACTOR) {
-
             for (LabelWidget labelWidget : labelWidgets) {
                 labelWidget.setVisible(false);
             }
@@ -263,19 +225,15 @@
             getScene().getGraphics().setComposite(oldComposite);
         }
     }
- 
+
     @Override
     public JPopupMenu getPopupMenu(Widget widget, Point point) {
         JPopupMenu menu = diagramScene.createPopupMenu();
         menu.addSeparator();
-
-        JMenu predecessors = new JMenu("Nodes Above");
-        predecessors.addMenuListener(new NeighborMenuListener(predecessors, getFigure(), false));
-        menu.add(predecessors);
-
-        JMenu successors = new JMenu("Nodes Below");
-        successors.addMenuListener(new NeighborMenuListener(successors, getFigure(), true));
-        menu.add(successors);
+        
+        build(menu, getFigure(), this, false, diagramScene);
+        menu.addSeparator();
+        build(menu, getFigure(), this, true, diagramScene);
 
         if (getFigure().getSubgraphs() != null) {
             menu.addSeparator();
@@ -283,7 +241,7 @@
             menu.add(subgraphs);
 
             final GraphViewer viewer = Lookup.getDefault().lookup(GraphViewer.class);
-            for(final InputGraph subgraph : getFigure().getSubgraphs()) {
+            for (final InputGraph subgraph : getFigure().getSubgraphs()) {
                 Action a = new AbstractAction() {
 
                     @Override
@@ -301,10 +259,45 @@
         return menu;
     }
 
+    public static void build(JPopupMenu menu, Figure figure, FigureWidget figureWidget, boolean successors, DiagramScene diagramScene) {
+        Set<Figure> set = figure.getPredecessorSet();
+        if (successors) {
+            set = figure.getSuccessorSet();
+        }
+
+        boolean first = true;
+        for (Figure f : set) {
+            if (f == figure) {
+                continue;
+            }
+
+            if (first) {
+                first = false;
+            } else {
+                menu.addSeparator();
+            }
+
+            Action go = diagramScene.createGotoAction(f);
+            menu.add(go);
+
+            JMenu preds = new JMenu("Nodes Above");
+            preds.addMenuListener(figureWidget.new NeighborMenuListener(preds, f, false));
+            menu.add(preds);
+
+            JMenu succs = new JMenu("Nodes Below");
+            succs.addMenuListener(figureWidget.new NeighborMenuListener(succs, f, true));
+            menu.add(succs);
+        }
+
+        if (figure.getPredecessorSet().isEmpty() && figure.getSuccessorSet().isEmpty()) {
+            menu.add("(none)");
+        }
+    }
+
     /**
      * Builds the submenu for a figure's neighbors on demand.
      */
-    private class NeighborMenuListener implements MenuListener {
+    public class NeighborMenuListener implements MenuListener {
 
         private final JMenu menu;
         private final Figure figure;
@@ -323,38 +316,7 @@
                 return;
             }
 
-            Set<Figure> set = figure.getPredecessorSet();
-            if (successors) {
-                set = figure.getSuccessorSet();
-            }
-
-            boolean first = true;
-            for (Figure f : set) {
-                if (f == figure) {
-                    continue;
-                }
-
-                if (first) {
-                    first = false;
-                } else {
-                    menu.addSeparator();
-                }
-
-                Action go = diagramScene.createGotoAction(f);
-                menu.add(go);
-
-                JMenu preds = new JMenu("Nodes Above");
-                preds.addMenuListener(new NeighborMenuListener(preds, f, false));
-                menu.add(preds);
-
-                JMenu succs = new JMenu("Nodes Below");
-                succs.addMenuListener(new NeighborMenuListener(succs, f, true));
-                menu.add(succs);
-            }
-
-            if (menu.getItemCount() == 0) {
-                menu.add("(none)");
-            }
+            build(menu.getPopupMenu(), figure, FigureWidget.this, successors, diagramScene);
         }
 
         @Override
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/LineWidget.java	Sat Mar 21 15:41:38 2015 +0100
@@ -109,7 +109,6 @@
         if (connections.size() > 0) {
             color = connections.get(0).getColor();
         }
-
         this.setToolTipText("<HTML>" + generateToolTipText(this.connections) + "</HTML>");
 
         this.setCheckClipping(true);
@@ -203,7 +202,7 @@
         g.drawLine(from.x, from.y, to.x, to.y);
 
         boolean sameFrom = false;
-        boolean sameTo = successors.size() == 0;
+        boolean sameTo = successors.isEmpty();
         for (LineWidget w : successors) {
             if (w.getFrom().equals(getTo())) {
                 sameTo = true;
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/OutputSlotWidget.java	Sat Mar 21 15:41:38 2015 +0100
@@ -41,12 +41,9 @@
     public OutputSlotWidget(OutputSlot slot, DiagramScene scene, Widget parent, FigureWidget fw) {
         super(slot, scene, parent, fw);
         outputSlot = slot;
-        //init();
-        //getFigureWidget().getRightWidget().addChild(this);
         Point p = outputSlot.getRelativePosition();
         p.y += getSlot().getFigure().getHeight() - Figure.SLOT_START;
         p.x -= this.calculateClientArea().width / 2;
-        //p.x += this.calculateClientArea().width / 2;
         this.setPreferredLocation(p);
     }
 
@@ -56,21 +53,9 @@
 
     @Override
     protected int calculateSlotWidth() {
-        
         List<OutputSlot> slots = getSlot().getFigure().getOutputSlots();
         assert slots.contains(getSlot());
         return calculateWidth(slots.size());
         
     }
-    /*
-    protected Point calculateRelativeLocation() {
-        if (getFigureWidget().getBounds() == null) {
-            return new Point(0, 0);
-        }
-
-        double x = this.getFigureWidget().getBounds().width;
-        List<OutputSlot> slots = outputSlot.getFigure().getOutputSlots();
-        assert slots.contains(outputSlot);
-        return new Point((int) x, (int) (calculateRelativeY(slots.size(), slots.indexOf(outputSlot))));
-    }*/
 }
--- a/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java	Fri Mar 20 18:33:31 2015 +0100
+++ b/src/share/tools/IdealGraphVisualizer/View/src/com/sun/hotspot/igv/view/widgets/SlotWidget.java	Sat Mar 21 15:41:38 2015 +0100
@@ -59,17 +59,16 @@
         this.setToolTipText("<HTML>" + slot.getToolTipText() + "</HTML>");
         this.setCheckClipping(true);
         parent.addChild(this);
-        
+
         //this.setPreferredBounds(this.calculateClientArea());
     }
-    
-    
+
     @Override
     protected void notifyStateChanged(ObjectState previousState, ObjectState state) {
         super.notifyStateChanged(previousState, state);
-	repaint();
+        repaint();
     }
-    
+
     public Slot getSlot() {
         return slot;
     }
@@ -86,58 +85,59 @@
         }
 
         Graphics2D g = this.getGraphics();
-       // g.setColor(Color.DARK_GRAY);
+        // g.setColor(Color.DARK_GRAY);
         int w = this.getBounds().width;
         int h = this.getBounds().height;
 
-        if(getSlot().getSource().getSourceNodes().size() > 0) {
+        if (getSlot().getSource().getSourceNodes().size() > 0) {
             final int SMALLER = 0;
             g.setColor(getSlot().getColor());
 
             int FONT_OFFSET = 2;
-            
+
             int s = h - SMALLER;
             int rectW = s;
-            
+
             Font font = this.getSlot().getFigure().getDiagram().getSlotFont();
-            if(this.getState().isSelected()) {
+            if (this.getState().isSelected()) {
                 font = font.deriveFont(Font.BOLD);
             }
-            
+
             if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0) {
                 g.setFont(font);
                 Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g);
-                rectW = (int)r1.getWidth() + FONT_OFFSET * 2;
+                rectW = (int) r1.getWidth() + FONT_OFFSET * 2;
             }
-            g.fillRect(w/2 - rectW/2, 0, rectW-1, s-1);
-            
-            if(this.getState().isHighlighted()) {
+            g.fillRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1);
+
+            if (this.getState().isHighlighted()) {
                 g.setColor(Color.BLUE);
             } else {
                 g.setColor(Color.BLACK);
             }
-            g.drawRect(w/2 - rectW/2, 0, rectW-1, s-1);
-            
-            
+            g.drawRect(w / 2 - rectW / 2, 0, rectW - 1, s - 1);
+
             if (getSlot().getShortName() != null && getSlot().getShortName().length() > 0 && getScene().getZoomFactor() >= TEXT_ZOOM_FACTOR) {
                 Rectangle2D r1 = g.getFontMetrics().getStringBounds(getSlot().getShortName(), g);
-                g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent()-1);//(int) (r1.getHeight()));
+                g.drawString(getSlot().getShortName(), (int) (w - r1.getWidth()) / 2, g.getFontMetrics().getAscent() - 1);//(int) (r1.getHeight()));
             }
-            
+
         } else {
 
-            if(this.getState().isHighlighted()) {
-                g.setColor(Color.BLUE);
+            if (this.getSlot().getConnections().isEmpty()) {
+                if (this.getState().isHighlighted()) {
+                    g.setColor(Color.BLUE);
+                } else {
+                    g.setColor(Color.BLACK);
+                }
+                int r = 2;
+                if (slot instanceof OutputSlot) {
+                    g.fillOval(w / 2 - r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2 * r, 2 * r);
+                } else {
+                    g.fillOval(w / 2 - r, Figure.SLOT_START - r, 2 * r, 2 * r);
+                }
             } else {
-                g.setColor(Color.BLACK);
-            }
-            int r = 2;
-            if (slot instanceof OutputSlot) {
-                g.fillOval(w/2-r, Figure.SLOT_WIDTH - Figure.SLOT_START - r, 2*r, 2*r);
-                //g.fillArc(w / 2 - r, -r, 2*r, 2*r, 180, 180);
-            } else {
-                g.fillOval(w/2-r, Figure.SLOT_START - r, 2*r, 2*r);
-                //g.fillArc(w / 2 - r, h - r, 2*r, 2*r, 0, 180);
+                // Do not paint a slot without connections.
             }
         }
     }
@@ -146,9 +146,9 @@
     protected Rectangle calculateClientArea() {
         return new Rectangle(0, 0, slot.getWidth(), Figure.SLOT_WIDTH);
     }
- 
+
     protected abstract int calculateSlotWidth();
-    
+
     protected int calculateWidth(int count) {
         return getFigureWidget().getFigure().getWidth() / count;
     }
@@ -158,19 +158,19 @@
         Set<Integer> hiddenNodes = new HashSet<>(diagramScene.getModel().getHiddenNodes());
         if (diagramScene.isAllVisible()) {
             hiddenNodes = new HashSet<>(diagramScene.getModel().getGraphToView().getGroup().getAllNodes());
-        } 
+        }
 
         boolean progress = false;
-        for(Figure f : diagramScene.getModel().getDiagramToView().getFigures()) {
-            for(Slot s : f.getSlots()) {
-                if(DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) {
+        for (Figure f : diagramScene.getModel().getDiagramToView().getFigures()) {
+            for (Slot s : f.getSlots()) {
+                if (DiagramScene.doesIntersect(s.getSource().getSourceNodesAsSet(), slot.getSource().getSourceNodesAsSet())) {
                     progress = true;
                     hiddenNodes.removeAll(f.getSource().getSourceNodesAsSet());
                 }
             }
         }
 
-        if(progress) {
+        if (progress) {
             this.diagramScene.getModel().showNot(hiddenNodes);
         }
     }